diff options
Diffstat (limited to 'arch/arm/mach-ux500')
176 files changed, 45255 insertions, 1338 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 6625e5bbf4d..d753fff92b1 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -1,42 +1,277 @@ if ARCH_U8500 -config UX500_SOC_COMMON +# Old bootloaders pass the Nomadik machine type, and the MACH_ option named +# after the machine type must be present and selected for machine_is_*() to +# work +config MACH_NOMADIK bool - default y - select ARM_GIC - select HAS_MTU - select NOMADIK_GPIO -config UX500_SOC_DB8500 +config MACH_HREFV60 bool +config MACH_SNOWBALL + bool + +choice + prompt "Ux500 platform" + default UX500_SOC_DB8500 + +config UX500_SOC_DB8500 + select CPU_V7 + select ARM_GIC + select SMP + select ARM_ERRATA_753970 + select SYS_SOC + bool "U8500" + config UX500_SOC_DB5500 + select CPU_V7 + select ARM_GIC + bool "U5500" + +endchoice + +config UX500_SVP bool +if UX500_SOC_DB8500 + +menu "U8500 Machines" + +config MACH_SVP8500V1 + bool "U8500 Simulator v1 (SVP8500v1)" + select UX500_SVP + help + Support Simulation for u8500 platform (v1) + +config MACH_SVP8500V2 + bool "U8500 Simulator v2 (SVP8500v2)" + select UX500_SVP + help + Supports Simulation for u8500 platform (v2) + +config MACH_U8500 + bool "U8500 MOP500/HREF/custom HW" + select MACH_NOMADIK + select MACH_HREFV60 + help + Supports the generic U8500 board type used for MOP500/HREF and some + custom boards. Boards using the generic type cannot be built + together; select the specific board in the "U8500 HW" option. + +config MACH_SNOWBALL + bool "U8500 Snowball" + select MACH_U8500 + select MACH_NOMADIK + help + Supports the Snowball board + +# If you are porting onto a new board, you really should be using a new machine +# type and adding an entry into this list, not the "U8500 HW" list below. + +endmenu + +if MACH_U8500 + choice - prompt "Ux500 target platform" + prompt "U8500 HW" default MACH_U8500_MOP config MACH_U8500_MOP - bool "U8500 Development platform" - select UX500_SOC_DB8500 + bool "MOP500/HREF" + help + Supports MOP500/HREF development boards. + +config MACH_U8500_SNOWBALL + bool "u8500 snowball" + help + Support for the u8500 snowball board. + +config MACH_U8500_PDP + bool "PDP" + help + Supports PDP target board + +endchoice + +endif + +endif + +if UX500_SOC_DB5500 + +menu "U5500 Machines" + +config MACH_SVP5500 + bool "U5500 Simulator (SVP5500)" + select UX500_SVP + help + Support for the U5500 Simulator + +config MACH_B5500 + bool "U5500 Big Board (B5500)" + help + Support for the U5500 Big Board +endmenu + +endif + +choice + prompt "Ux500 UIB Keylayout" + default KEYLAYOUT_LAYOUT1 + +config KEYLAYOUT_LAYOUT1 + bool "UIB Keylayout 1; for generic users" help - Include support for mop500 development platform - based on U8500 architecture. The platform is based - on early drop silicon version of 8500. + Supported keylayout for some numerics, power/call buttons, + volume control etc -config MACH_U5500 - bool "U5500 Development platform" - select UX500_SOC_DB5500 +config KEYLAYOUT_LAYOUT2 + bool "UIB Keylayout 2; for connectivity users" help - Include support for the U5500 development platform. + Supports keylayout numerics 0-9, left/right/up/down/back/ + enter keys and special character "."(dot) + endchoice +choice + prompt "Ux500 sched_clock timer" + default UX500_MTU_TIMER + +config U8500_PRCMU_TIMER + bool "PRCMU Timer sched_clock" + depends on (UX500_SOC_DB8500 && !HAS_MTU) + help + Add support for an always on sched_clock, required for + proper cpuidle and suspend. + +config UX500_MTU_TIMER + bool "Multi Timer Unit sched_clock" + help + Add sched_clock support for the Multi Timer Unit. + Since mtu isn't always on cpuidle will not + work with this clock. + +endchoice + +config U8500_PRCMU + bool "U8500 PRCMU support" + depends on UX500_SOC_DB8500 + default n + help + Add support for PRCMU for U8500 + +config U5500_PRCMU + bool "U5500 PRCMU support" + depends on UX500_SOC_DB5500 + default y + help + Add support for PRCMU for U5500 + +config UX500_PRCMU_QOS_POWER + bool "UX500 PRCMU power QoS support" + depends on (U5500_PRCMU || U8500_PRCMU) + default y + help + Add support for PRCMU power Quality of Service + +config UX500_PRCMU_DEBUG + bool "PRCMU debug" + depends on ((U5500_PRCMU || U8500_PRCMU) && DEBUG_FS) + default n + help + Add support for PRCMU debug + +config U8500_REGULATOR_DEBUG + bool "Regulator debug support" + depends on REGULATOR_VIRTUAL_CONSUMER + default n + help + Add support for U8500 regulator debug + +config U5500_PWM + bool "PWM support" + default y + depends on UX500_SOC_DB5500 + help + Add support for PWM for U5500 + +config MOP500_SDI + bool + default y + depends on ((MACH_U8500_MOP || \ + MACH_U8500_PDP || \ + MACH_U8500_SNOWBALL) && MMC_ARMMMCI) + +config ARCH_HAS_CPU_IDLE_WAIT + def_bool y + config UX500_DEBUG_UART int "Ux500 UART to use for low-level debug" - default 2 + default 2 if UX500_SOC_DB8500 + default 0 if UX500_SOC_DB5500 help Choose the UART on which kernel low-level debug messages should be output. + +config SENSORS1P_MOP + tristate "HAL and Proximity sensors support" + depends on REGULATOR && (GPIO_STMPE2401 || GPIO_TC35892) + default y + help + Add support for Osram's SFH7741 Proximity Sensor and Samsumg + HED54XXU11 HAL Switch + +config U5500_MODEM_IRQ + bool "Modem IRQ support" + depends on UX500_SOC_DB5500 + default y + help + Add support for handling IRQ:s from modem side + +config MOP500_NUIB + bool "MOP500 NUIB" + depends on MACH_U8500_MOP + default y + help + Add support for the platform data of synaptics rmi4 driver + +config TEE_UX500 + bool "Trusted Execution Environment (TEE) ux500 hardware support" + depends on TEE_SUPPORT + default y + help + Adds TEE hardware support for ux500 platforms. + +config TEE_SVP + bool "Trusted Execution Environment (TEE) ux500 SVP support" + depends on TEE_SUPPORT && UX500_SVP + default y + help + Adds TEE support for SVP in ux500 platforms. + +config DB8500_MLOADER + bool "Modem firmware upload/download support" + depends on UX500_SOC_DB8500 + select DBX500_MLOADER + default n + help + Adds Modem firmware upload/download support to DB8500. + +config UX500_DEBUG_HWREG + bool "Debug hardware registers from userspace" + depends on (DEBUG_FS && UX500_SOC_DB8500) + help + Adds various debug files to access registers. + This should never ever be used for anything else than debugging. + +config UX500_DEBUG_NO_LAUTERBACH + bool "Disable clocks needed for Lauterbach debugging" + help + Disable clocks needed for Lauterbach debugging at boot. + If yes, you will reduce the power consumption. + +source "arch/arm/mach-ux500/Kconfig-arch" +source "arch/arm/mach-ux500/pm/Kconfig" endif diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch new file mode 100644 index 00000000000..3f590aaadc5 --- /dev/null +++ b/arch/arm/mach-ux500/Kconfig-arch @@ -0,0 +1,160 @@ +config GPIO_STM + bool "STM GPIO driver support" + default y + help + Say yes here to support the STM GPIO device + +config U8500_SECURE + bool "Support for running in Secure mode" + default n + help + Build the kernel to run in Secure mode. + +#Configuration for MCDE setup + +if FB_MCDE + +menu "Display selection" + +config DISPLAY_GENERIC_PRIMARY + bool "Generic primary display support" + depends on (MACH_U8500_MOP || MACH_B5500) + default y + +choice + prompt "Display port type" + depends on DISPLAY_GENERIC_PRIMARY + default DISPLAY_GENERIC_DSI_PRIMARY + help + Select the kind of display port used for the primary display + +config DISPLAY_GENERIC_DSI_PRIMARY + bool "DSI display" + select MCDE_DISPLAY_GENERIC_DSI + help + Say yes here when using a DSI display + +config MCDE_DISPLAY_DPI_PRIMARY + bool "DPI display" + select MCDE_DISPLAY_DPI + depends on MACH_8500_MOP + help + Say yes here when using a DPI display + +endchoice + +choice + prompt "Color depth" + depends on DISPLAY_GENERIC_PRIMARY + default MCDE_DISPLAY_PRIMARY_16BPP + help + Select color depth for primary display + +config MCDE_DISPLAY_PRIMARY_16BPP + bool "16 bpp" + help + 16 bpp color depth + +config MCDE_DISPLAY_PRIMARY_32BPP + bool "32 bpp" + help + 32 bpp color depth + +endchoice + +choice DISPLAY_GENERIC_DSI_PRIMARY_ROTATION + prompt "Enable main display rotation" + depends on DISPLAY_GENERIC_DSI_PRIMARY + default DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_90 + help + Set rotation of main display + +config DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_0 + bool "0 degrees" +config DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_90 + bool "90 degrees" +config DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_180 + bool "180 degrees" +config DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_270 + bool "270 degrees" +endchoice + +config DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE + int + depends on DISPLAY_GENERIC_DSI_PRIMARY + default "0" if DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_0 + default "90" if DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_90 + default "180" if DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_180 + default "270" if DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_270 + +config DISPLAY_SONY_SY35560_DSI_PRIMARY + bool "Sony SY35560 primary display support" + depends on MACH_U8500_PDP + select MCDE_DISPLAY_SONY_SY35560_DSI + default y + help + Say yes here if main display exists + +config DISPLAY_GENERIC_DSI_PRIMARY_VSYNC + bool "Enable v-sync for primary display" + depends on DISPLAY_GENERIC_DSI_PRIMARY || DISPLAY_SONY_SY35560_DSI_PRIMARY + default n + help + Say yes to enable v-sync for primary display + +config DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC + bool "Enable auto sync for primary display" + depends on DISPLAY_GENERIC_DSI_PRIMARY + default n + help + Say yes to enable auto sync for primary display + +config SONY_SY35560_ENABLE_ESD_CHECK + bool "Enable esd status check for primary display" + depends on DISPLAY_SONY_SY35560_DSI_PRIMARY + default n + help + Say yes to enable esd status check for primary display + +config DISPLAY_GENERIC_DSI_SECONDARY + bool "Sub display support" + depends on MACH_U8500 + select MCDE_DISPLAY_GENERIC_DSI + help + Say yes here if sub display exists + +config DISPLAY_GENERIC_DSI_SECONDARY_VSYNC + bool "Enable v-sync for secondary display" + depends on DISPLAY_GENERIC_DSI_SECONDARY + help + Say yes to enable v-sync for secondary display + +config DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC + bool "Enable auto sync for secondary display" + depends on DISPLAY_GENERIC_DSI_SECONDARY + help + Say yes to enable auto sync for secondary display + +config DISPLAY_AB8500_TERTIARY + bool "AB8500 TVout display support" + depends on MACH_U8500 && !AV8100_SDTV + select MCDE_DISPLAY_AB8500_DENC + help + Say yes here if tv out support + +config DISPLAY_AV8100_TERTIARY + bool "AV8100 HDMI/CVBS display support" + depends on (MACH_U8500_MOP || MACH_B5500 || MACH_U8500_SNOWBALL) + select MCDE_DISPLAY_AV8100 + help + Say yes here if HDMI output support + +config DISPLAY_AV8100_TRIPPLE_BUFFER + bool "Enable tripple buffer for HDMI display" + depends on DISPLAY_AV8100_TERTIARY + help + Say yes to enable tripple buffer. You'll get double buffer otherwise + +endmenu + +endif diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 4556aea9c3c..91bc0036594 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -2,10 +2,86 @@ # Makefile for the linux kernel, U8500 machine. # -obj-y := clock.o cpu.o devices.o -obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o -obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o -obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o -obj-$(CONFIG_MACH_U5500) += board-u5500.o -obj-$(CONFIG_SMP) += platsmp.o headsmp.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o +ifeq ($(CONFIG_CRYPTO_DEV_UX500_HASH), m) + CFLAGS_devices.o += -DCONFIG_CRYPTO_DEV_UX500_HASH + CFLAGS_board-mop500.o += -DCONFIG_CRYPTO_DEV_UX500_HASH +endif + +obj-y := clock.o timer-mtu.o \ + devices-common.o pins.o dcache.o reboot_reasons.o +obj-$(CONFIG_PM) += pm/ +obj-$(CONFIG_REGULATOR) += regulator-ux500.o + +ifeq ($(CONFIG_UX500_SOC_DB8500), y) +obj-$(CONFIG_REGULATOR) += regulator-u8500.o +obj-$(CONFIG_MFD_CG2900) += devices-cg2900-u8500.o +endif + +ifeq ($(CONFIG_UX500_SOC_DB5500), y) +obj-$(CONFIG_REGULATOR) += regulator-u5500.o +obj-$(CONFIG_MFD_CG2900) += devices-cg2900-u5500.o +endif + +obj-$(CONFIG_U8500_REGULATOR_DEBUG) += virt-regulator-u8500.o +obj-$(CONFIG_ARCH_U8500) += devices.o cpu.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_MACH_B5500) += board-u5500.o board-u5500-mcde.o \ + board-u5500-sdi.o \ + board-u5500-regulators.o \ + board-u5500-pins.o \ + board-u5500-cg2900.o +obj-$(CONFIG_MACH_SVP5500) += board-svp5500.o +obj-$(CONFIG_U8500_MMIO) += board-mop500-mmio.o +obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-msp.o board-mop500-uib.o \ + board-mop500-stuib.o board-mop500-u8500uib.o \ + board-mop500-pins.o board-mop500-bm.o \ + board-mop500-regulators.o \ + cw1200-wlan.o +obj-$(CONFIG_MACH_U8500_PDP) += board-mop500.o board-mop500-msp.o board-mop500-bm.o \ + board-mop500-pins.o board-mop500-regulators.o + # until pdp-specific files are there +obj-$(CONFIG_MACH_U8500_SNOWBALL) += board-mop500.o board-mop500-msp.o \ + board-mop500-pins.o board-mop500-bm.o \ + board-snowball-netdev.o board-snowball-digio.o \ + board-mop500-uib.o board-mop500-stuib.o board-mop500-u8500uib.o \ + board-mop500-regulators.o cw1200-wlan.o +#obj-$(CONFIG_MACH_U8500_SNOWBALL) += board-snowball.o board-mop500-msp.o \ +# board-snowball-pins.o \ +# board-snowball-netdev.o board-snowball-digio.o # add board-mop500-bm.o ??? +obj-$(CONFIG_MOP500_SDI) += board-mop500-sdi.o +obj-$(CONFIG_UX500_SOC_DB5500) += devices-db5500.o cpu-db5500.o \ + dma-db5500.o timer-db8500.o \ + clock-db5500.o clock-debug.o +obj-$(CONFIG_UX500_SOC_DB8500) += devices-db8500.o \ + cpu-db8500.o dma-db8500.o\ + uart-db8500.o clock-db8500.o +obj-$(CONFIG_UX500_SOC_DB8500) += timer-rtt.o timer-db8500.o timer-db8500-prcmu.o +obj-$(CONFIG_MACH_U8500_PDP) += board-pdp-mcde.o +obj-$(CONFIG_MACH_U8500_MOP) += board-mop500-mcde.o +obj-$(CONFIG_MACH_U8500_SNOWBALL) += board-mop500-mcde.o +obj-$(CONFIG_MACH_SVP8500V1) += board-svp8500.o +obj-$(CONFIG_MACH_SVP8500V2) += board-svp8500.o +obj-$(CONFIG_MACH_U5500_SIMULATOR) += board-u5500.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_U8500_PRCMU) += prcmu-db8500.o +obj-$(CONFIG_U5500_PRCMU) += prcmu-db5500.o +obj-$(CONFIG_UX500_PRCMU_QOS_POWER) += prcmu-qos-power.o +obj-$(CONFIG_UX500_PRCMU_DEBUG) += prcmu-debug.o +obj-$(CONFIG_SENSORS1P_MOP) += sensors1p.o +obj-$(CONFIG_MACH_U5500_BB) += board-u5500.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_USB) += musb_db8500.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o +obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o +obj-$(CONFIG_U5500_PWM) += pwm.o +obj-$(CONFIG_MOP500_NUIB) += board-mop500-nuib.o +obj-$(CONFIG_DB8500_MLOADER) += mloader-db8500.o + +obj-$(CONFIG_TEE_UX500) += tee_ux500.o +obj-$(CONFIG_TEE_SVP) += tee_service_svp.o +obj-$(CONFIG_TEE_SVP) += tee_ta_start_modem_svp.o +obj-$(CONFIG_MFD_CG2900) += devices-cg2900.o +obj-$(CONFIG_UX500_DEBUG_HWREG) += hwreg.o +obj-$(CONFIG_HWMEM) += hwmem-int.o + diff --git a/arch/arm/mach-ux500/board-mop500-bm.c b/arch/arm/mach-ux500/board-mop500-bm.c new file mode 100644 index 00000000000..923392cf1be --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-bm.c @@ -0,0 +1,418 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL), version 2 + * + * U8500 board specific charger and battery initialization parameters. + * + * Author: Johan Palsson <johan.palsson@stericsson.com> for ST-Ericsson. + * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson. + * + */ + +#include <linux/power_supply.h> +#include <linux/mfd/ab8500/ab8500-bm.h> +#include "board-mop500-bm.h" + +#ifdef CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL +/* + * These are the defined batteries that uses a NTC and ID resistor placed + * inside of the battery pack. + * Note that the res_to_temp table must be strictly sorted by falling resistance + * values to work. + */ +static struct res_to_temp temp_tbl_A[] = { + {-5, 53407}, + { 0, 48594}, + { 5, 43804}, + {10, 39188}, + {15, 34870}, + {20, 30933}, + {25, 27422}, + {30, 24347}, + {35, 21694}, + {40, 19431}, + {45, 17517}, + {50, 15908}, + {55, 14561}, + {60, 13437}, + {65, 12500}, +}; +static struct res_to_temp temp_tbl_B[] = { + {-5, 165418}, + { 0, 159024}, + { 5, 151921}, + {10, 144300}, + {15, 136424}, + {20, 128565}, + {25, 120978}, + {30, 113875}, + {35, 107397}, + {40, 101629}, + {45, 96592}, + {50, 92253}, + {55, 88569}, + {60, 85461}, + {65, 82869}, +}; +static struct v_to_cap cap_tbl_A[] = { + {4171, 100}, + {4114, 95}, + {4009, 83}, + {3947, 74}, + {3907, 67}, + {3863, 59}, + {3830, 56}, + {3813, 53}, + {3791, 46}, + {3771, 33}, + {3754, 25}, + {3735, 20}, + {3717, 17}, + {3681, 13}, + {3664, 8}, + {3651, 6}, + {3635, 5}, + {3560, 3}, + {3408, 1}, + {3247, 0}, +}; +static struct v_to_cap cap_tbl_B[] = { + {4161, 100}, + {4124, 98}, + {4044, 90}, + {4003, 85}, + {3966, 80}, + {3933, 75}, + {3888, 67}, + {3849, 60}, + {3813, 55}, + {3787, 47}, + {3772, 30}, + {3751, 25}, + {3718, 20}, + {3681, 16}, + {3660, 14}, + {3589, 10}, + {3546, 7}, + {3495, 4}, + {3404, 2}, + {3250, 0}, +}; +#endif +static struct v_to_cap cap_tbl[] = { + {4186, 100}, + {4163, 99}, + {4114, 95}, + {4068, 90}, + {3990, 80}, + {3926, 70}, + {3898, 65}, + {3866, 60}, + {3833, 55}, + {3812, 50}, + {3787, 40}, + {3768, 30}, + {3747, 25}, + {3730, 20}, + {3705, 15}, + {3699, 14}, + {3684, 12}, + {3672, 9}, + {3657, 7}, + {3638, 6}, + {3556, 4}, + {3424, 2}, + {3317, 1}, + {3094, 0}, +}; + +/* + * Note that the res_to_temp table must be strictly sorted by falling + * resistance values to work. + */ +static struct res_to_temp temp_tbl[] = { + {-5, 214834}, + { 0, 162943}, + { 5, 124820}, + {10, 96520}, + {15, 75306}, + {20, 59254}, + {25, 47000}, + {30, 37566}, + {35, 30245}, + {40, 24520}, + {45, 20010}, + {50, 16432}, + {55, 13576}, + {60, 11280}, + {65, 9425}, +}; + +static const struct battery_type bat_type[] = { + [BATTERY_UNKNOWN] = { + /* First element always represent the UNKNOWN battery */ + .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, + .resis_high = 0, + .resis_low = 0, + .battery_resistance = 300, + .charge_full_design = 612, + .nominal_voltage = 3700, + .termination_vol = 4050, + .termination_curr = 200, + .recharge_vol = 3990, + .normal_cur_lvl = 400, + .normal_vol_lvl = 4100, + .maint_a_cur_lvl = 400, + .maint_a_vol_lvl = 4050, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 400, + .maint_b_vol_lvl = 4000, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + }, + +#ifdef CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL + { + .name = POWER_SUPPLY_TECHNOLOGY_LIPO, + .resis_high = 53407, + .resis_low = 12500, + .battery_resistance = 300, + .charge_full_design = 900, + .nominal_voltage = 3600, + .termination_vol = 4150, + .termination_curr = 80, + .recharge_vol = 4130, + .normal_cur_lvl = 700, + .normal_vol_lvl = 4200, + .maint_a_cur_lvl = 600, + .maint_a_vol_lvl = 4150, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 600, + .maint_b_vol_lvl = 4100, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A), + .r_to_t_tbl = temp_tbl_A, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A), + .v_to_cap_tbl = cap_tbl_A, + + }, + { + .name = POWER_SUPPLY_TECHNOLOGY_LIPO, + .resis_high = 165418, + .resis_low = 82869, + .battery_resistance = 300, + .charge_full_design = 900, + .nominal_voltage = 3600, + .termination_vol = 4150, + .termination_curr = 80, + .recharge_vol = 4130, + .normal_cur_lvl = 700, + .normal_vol_lvl = 4200, + .maint_a_cur_lvl = 600, + .maint_a_vol_lvl = 4150, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 600, + .maint_b_vol_lvl = 4100, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B), + .r_to_t_tbl = temp_tbl_B, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B), + .v_to_cap_tbl = cap_tbl_B, + }, +#else +/* + * These are the batteries that doesn't have an internal NTC resistor to measure + * its temperature. The temperature in this case is measure with a NTC placed + * near the battery but on the PCB. + */ + { + .name = POWER_SUPPLY_TECHNOLOGY_LIPO, + .resis_high = 76000, + .resis_low = 53000, + .battery_resistance = 300, + .charge_full_design = 900, + .nominal_voltage = 3700, + .termination_vol = 4150, + .termination_curr = 100, + .recharge_vol = 4130, + .normal_cur_lvl = 700, + .normal_vol_lvl = 4200, + .maint_a_cur_lvl = 600, + .maint_a_vol_lvl = 4150, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 600, + .maint_b_vol_lvl = 4100, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + }, + { + .name = POWER_SUPPLY_TECHNOLOGY_LION, + .resis_high = 30000, + .resis_low = 10000, + .battery_resistance = 300, + .charge_full_design = 950, + .nominal_voltage = 3700, + .termination_vol = 4150, + .termination_curr = 100, + .recharge_vol = 4130, + .normal_cur_lvl = 700, + .normal_vol_lvl = 4200, + .maint_a_cur_lvl = 600, + .maint_a_vol_lvl = 4150, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 600, + .maint_b_vol_lvl = 4100, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + }, + { + .name = POWER_SUPPLY_TECHNOLOGY_LION, + .resis_high = 95000, + .resis_low = 76001, + .battery_resistance = 300, + .charge_full_design = 950, + .nominal_voltage = 3700, + .termination_vol = 4150, + .termination_curr = 100, + .recharge_vol = 4130, + .normal_cur_lvl = 700, + .normal_vol_lvl = 4200, + .maint_a_cur_lvl = 600, + .maint_a_vol_lvl = 4150, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 600, + .maint_b_vol_lvl = 4100, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + }, +#endif +}; + +static char *ab8500_charger_supplied_to[] = { + "ab8500_chargalg", + "ab8500_fg", + "ab8500_btemp", +}; + +static char *ab8500_btemp_supplied_to[] = { + "ab8500_chargalg", + "ab8500_fg", +}; + +static char *ab8500_fg_supplied_to[] = { + "ab8500_chargalg", +}; + +static char *ab8500_chargalg_supplied_to[] = { + "ab8500_fg", +}; + +struct ab8500_charger_platform_data ab8500_charger_plat_data = { + .supplied_to = ab8500_charger_supplied_to, + .num_supplicants = ARRAY_SIZE(ab8500_charger_supplied_to), +}; + +struct ab8500_btemp_platform_data ab8500_btemp_plat_data = { + .supplied_to = ab8500_btemp_supplied_to, + .num_supplicants = ARRAY_SIZE(ab8500_btemp_supplied_to), +}; + +struct ab8500_fg_platform_data ab8500_fg_plat_data = { + .supplied_to = ab8500_fg_supplied_to, + .num_supplicants = ARRAY_SIZE(ab8500_fg_supplied_to), +}; + +struct ab8500_chargalg_platform_data ab8500_chargalg_plat_data = { + .supplied_to = ab8500_chargalg_supplied_to, + .num_supplicants = ARRAY_SIZE(ab8500_chargalg_supplied_to), +}; + +static const struct ab8500_bm_capacity_levels cap_levels = { + .critical = 2, + .low = 10, + .normal = 70, + .high = 95, + .full = 100, +}; + +static const struct ab8500_fg_parameters fg = { + .recovery_sleep_timer = 10, + .recovery_total_time = 100, + .init_timer = 1, + .init_discard_time = 5, + .init_total_time = 40, + .high_curr_time = 60, + .accu_charging = 30, + .accu_high_curr = 30, + .high_curr_threshold = 50, + .lowbat_threshold = 3100, +}; + +static const struct ab8500_maxim_parameters maxi_params = { + .ena_maxi = true, + .chg_curr = 910, + .wait_cycles = 10, + .charger_curr_step = 100, +}; + +static const struct ab8500_bm_charger_parameters chg = { + .usb_volt_max = 5500, + .usb_curr_max = 1500, + .ac_volt_max = 7500, + .ac_curr_max = 1500, +}; + +struct ab8500_bm_data ab8500_bm_data = { + .temp_under = 3, + .temp_low = 8, + .temp_high = 55, + .temp_over = 60, + .main_safety_tmr_h = 4, + .usb_safety_tmr_h = 4, + .bkup_bat_v = BUP_VCH_SEL_2P6V, + .bkup_bat_i = BUP_ICH_SEL_150UA, + .no_maintenance = false, +#ifdef CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL + .adc_therm = ADC_THERM_BATCTRL, +#else + .adc_therm = ADC_THERM_BATTEMP, +#endif + .chg_unknown_bat = false, + .enable_overshoot = false, + .fg_res = 10, + .cap_levels = &cap_levels, + .bat_type = bat_type, + .n_btypes = ARRAY_SIZE(bat_type), + .batt_id = 0, + .interval_charging = 5, + .interval_not_charging = 120, + .temp_hysteresis = 3, + .maxi = &maxi_params, + .chg_params = &chg, + .fg_params = &fg, +}; diff --git a/arch/arm/mach-ux500/board-mop500-bm.h b/arch/arm/mach-ux500/board-mop500-bm.h new file mode 100644 index 00000000000..ec69a85468f --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-bm.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL), version 2 + * + * U8500 board specific charger and battery initialization parameters. + * + * Author: Johan Palsson <johan.palsson@stericsson.com> for ST-Ericsson. + * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson. + * + */ + +#ifndef __BOARD_MOP500_BM_H +#define __BOARD_MOP500_BM_H + +#include <linux/mfd/ab8500/ab8500-bm.h> + +extern struct ab8500_charger_platform_data ab8500_charger_plat_data; +extern struct ab8500_btemp_platform_data ab8500_btemp_plat_data; +extern struct ab8500_fg_platform_data ab8500_fg_plat_data; +extern struct ab8500_chargalg_platform_data ab8500_chargalg_plat_data; +extern struct ab8500_bm_data ab8500_bm_data; + +#endif diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c new file mode 100644 index 00000000000..07b01ddb1fc --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-mcde.c @@ -0,0 +1,790 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/mfd/ab8500/denc.h> +#include <linux/workqueue.h> +#include <linux/dispdev.h> +#include <video/av8100.h> +#include <video/mcde_display.h> +#include <video/mcde_display-generic_dsi.h> +#include <video/mcde_display-vuib500-dpi.h> +#include <video/mcde_display-av8100.h> +#include <video/mcde_display-ab8500.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> +#include <plat/pincfg.h> +#include "pins-db8500.h" +#include "pins.h" +#include "board-mop500.h" + +#define DSI_UNIT_INTERVAL_0 0x9 +#define DSI_UNIT_INTERVAL_1 0x9 +#define DSI_UNIT_INTERVAL_2 0x5 + +#define PRIMARY_DISPLAY_ID 0 +#define SECONDARY_DISPLAY_ID 1 +#define TERTIARY_DISPLAY_ID 2 + +#ifdef CONFIG_FB_MCDE + +/* The initialization of hdmi disp driver must be delayed in order to + * ensure that inputclk will be available (needed by hdmi hw) */ +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +static struct delayed_work work_dispreg_hdmi; +#define DISPREG_HDMI_DELAY 5000 +#endif + +#define MCDE_NR_OF_DISPLAYS 3 +static struct mcde_display_device *displays[MCDE_NR_OF_DISPLAYS] = { NULL }; +static int display_initialized_during_boot; + +static int __init startup_graphics_setup(char *str) +{ + + if (get_option(&str, &display_initialized_during_boot) != 1) + display_initialized_during_boot = 0; + + switch (display_initialized_during_boot) { + case 1: + pr_info("Startup graphics support\n"); + break; + case 0: + default: + pr_info("No startup graphics supported\n"); + break; + }; + + return 1; +} +__setup("startup_graphics=", startup_graphics_setup); + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY +static struct mcde_port port0 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 0, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, +#else + .sync_src = MCDE_SYNCSRC_BTA, + .update_auto_trig = false, +#endif + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_0, + .clk_cont = false, + .data_lanes_swap = false, + }, + }, +}; + +struct mcde_display_generic_platform_data generic_display0_pdata = { + .reset_delay = 1, +#ifdef CONFIG_REGULATOR + .regulator_id = "v-display", + .min_supply_voltage = 2500000, /* 2.5V */ + .max_supply_voltage = 2700000 /* 2.7V */ +#endif +}; + +struct mcde_display_device generic_display0 = { + .name = "mcde_disp_generic", + .id = PRIMARY_DISPLAY_ID, + .port = &port0, + .chnl_id = MCDE_CHNL_A, + /* + * A large fifo is needed when ddr is clocked down to 25% to not get + * latency problems. + */ + .fifo = MCDE_FIFO_A, +#ifdef CONFIG_MCDE_DISPLAY_PRIMARY_16BPP + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, +#else + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, +#endif + .native_x_res = 864, + .native_y_res = 480, + .synchronized_update = false, + /* TODO: Remove rotation buffers once ESRAM driver is completed */ + .rotbuf1 = U8500_ESRAM_BASE + 0x20000 * 4, + .rotbuf2 = U8500_ESRAM_BASE + 0x20000 * 4 + 0x10000, + .dev = { + .platform_data = &generic_display0_pdata, + }, +}; +#endif /* CONFIG_DISPLAY_GENERIC_DSI_PRIMARY */ + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY +static struct mcde_port subdisplay_port = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 1, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, +#else + .sync_src = MCDE_SYNCSRC_BTA, + .update_auto_trig = false, +#endif + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_1, + .clk_cont = false, + .data_lanes_swap = false, + }, + }, + +}; + +static struct mcde_display_generic_platform_data generic_subdisplay_pdata = { + .reset_delay = 1, +#ifdef CONFIG_REGULATOR + .regulator_id = "v-display", + .min_supply_voltage = 2500000, /* 2.5V */ + .max_supply_voltage = 2700000 /* 2.7V */ +#endif +}; + +static struct mcde_display_device generic_subdisplay = { + .name = "mcde_disp_generic_subdisplay", + .id = SECONDARY_DISPLAY_ID, + .port = &subdisplay_port, + .chnl_id = MCDE_CHNL_C1, + .fifo = MCDE_FIFO_C1, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 864, + .native_y_res = 480, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_VSYNC + .synchronized_update = true, +#else + .synchronized_update = false, +#endif + .dev = { + .platform_data = &generic_subdisplay_pdata, + }, +}; +#endif /* CONFIG_DISPLAY_GENERIC_DSI_SECONDARY */ + +#ifdef CONFIG_MCDE_DISPLAY_DPI_PRIMARY +static struct mcde_port port0 = { + .type = MCDE_PORTTYPE_DPI, + .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP, + .ifc = 0, + .link = 1, /* DPI channel B can only be on link 1 */ + .sync_src = MCDE_SYNCSRC_OFF, /* sync from output formatter */ + .update_auto_trig = true, + .phy = { + .dpi = { + .tv_mode = false, + .clock_div = 2, + .polarity = DPI_ACT_LOW_VSYNC | DPI_ACT_LOW_HSYNC, + }, + }, +}; + +struct mcde_display_dpi_platform_data generic_display0_pdata = {0}; +static struct ux500_pins *dpi_pins; + +static int dpi_display_platform_enable(struct mcde_display_device *ddev) +{ + int res; + + if (!dpi_pins) { + dpi_pins = ux500_pins_get("mcde-dpi"); + if (!dpi_pins) + return -EINVAL; + } + + dev_info(&ddev->dev, "%s\n", __func__); + res = ux500_pins_enable(dpi_pins); + if (res) + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + + return res; +} + +static int dpi_display_platform_disable(struct mcde_display_device *ddev) +{ + int res; + + dev_info(&ddev->dev, "%s\n", __func__); + + res = ux500_pins_disable(dpi_pins); + if (res) + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + + return res; + +} + +struct mcde_display_device generic_display0 = { + .name = "mcde_display_dpi", + .id = 0, + .port = &port0, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, +#ifdef CONFIG_MCDE_DISPLAY_PRIMARY_16BPP + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, +#else + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, +#endif + .native_x_res = 640, + .native_y_res = 480, + /* .synchronized_update: Don't care: port is set to update_auto_trig */ + .dev = { + .platform_data = &generic_display0_pdata, + }, + .platform_enable = dpi_display_platform_enable, + .platform_disable = dpi_display_platform_disable, +}; +#endif /* CONFIG_MCDE_DISPLAY_DPI_PRIMARY */ + +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY +static struct mcde_port port_tvout1 = { + .type = MCDE_PORTTYPE_DPI, + .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP, + .ifc = 0, + .link = 1, /* channel B */ + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, + .phy = { + .dpi = { + .bus_width = 4, /* DDR mode */ + .tv_mode = true, + .clock_div = MCDE_PORT_DPI_NO_CLOCK_DIV, + }, + }, +}; + +static struct ab8500_display_platform_data ab8500_display_pdata = { + .nr_regulators = 2, + .regulator_id = {"v-tvout", "v-ab8500-AV-switch"}, + .rgb_2_yCbCr_transform = { + .matrix = { + {0x42, 0x81, 0x19}, + {0xffda, 0xffb6, 0x70}, + {0x70, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, + } +}; + +static struct ux500_pins *tvout_pins; + +static int ab8500_platform_enable(struct mcde_display_device *ddev) +{ + int res = 0; + + if (!tvout_pins) { + tvout_pins = ux500_pins_get("mcde-tvout"); + if (!tvout_pins) + return -EINVAL; + } + + dev_info(&ddev->dev, "%s\n", __func__); + res = ux500_pins_enable(tvout_pins); + if (res != 0) + goto failed; + + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static int ab8500_platform_disable(struct mcde_display_device *ddev) +{ + int res; + + dev_info(&ddev->dev, "%s\n", __func__); + + res = ux500_pins_disable(tvout_pins); + if (res != 0) + goto failed; + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +struct mcde_display_device tvout_ab8500_display = { + .name = "mcde_tv_ab8500", + .id = TERTIARY_DISPLAY_ID, + .port = &port_tvout1, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 720, + .native_y_res = 576, + /* .synchronized_update: Don't care: port is set to update_auto_trig */ + .dev = { + .platform_data = &ab8500_display_pdata, + }, + + /* + * We might need to describe the std here: + * - there are different PAL / NTSC formats (do they require MCDE + * settings?) + */ + .platform_enable = ab8500_platform_enable, + .platform_disable = ab8500_platform_disable, +}; +#endif /* CONFIG_DISPLAY_AB8500_TERTIARY */ + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +static struct mcde_port port2 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 2, +#ifdef CONFIG_AV8100_HWTRIG_INT + .sync_src = MCDE_SYNCSRC_TE0, +#endif +#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3 + .sync_src = MCDE_SYNCSRC_TE1, +#endif +#ifdef CONFIG_AV8100_HWTRIG_DSI_TE + .sync_src = MCDE_SYNCSRC_TE_POLLING, +#endif +#ifdef CONFIG_AV8100_HWTRIG_NONE + .sync_src = MCDE_SYNCSRC_OFF, +#endif + .update_auto_trig = true, + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_2, + .clk_cont = false, + .data_lanes_swap = false, + }, + }, + .hdmi_sdtv_switch = HDMI_SWITCH, +}; + +struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = { + .reset_gpio = 0, + .reset_delay = 1, + .regulator_id = NULL, /* TODO: "display_main" */ + .cvbs_regulator_id = "v-av8100-AV-switch", + .ddb_id = 1, + .rgb_2_yCbCr_transform = { + .matrix = { + {0x42, 0x81, 0x19}, + {0xffda, 0xffb6, 0x70}, + {0x70, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, + } +}; + +struct mcde_display_device av8100_hdmi = { + .name = "av8100_hdmi", + .id = TERTIARY_DISPLAY_ID, + .port = &port2, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, + .native_x_res = 1280, + .native_y_res = 720, + .synchronized_update = false, + .dev = { + .platform_data = &av8100_hdmi_pdata, + }, + .platform_enable = NULL, + .platform_disable = NULL, +}; + +static void delayed_work_dispreg_hdmi(struct work_struct *ptr) +{ + if (mcde_display_device_register(&av8100_hdmi)) + pr_warning("Failed to register av8100_hdmi\n"); + displays[TERTIARY_DISPLAY_ID] = &av8100_hdmi; +} +#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */ + +/* +* This function will create the framebuffer for the display that is registered. +*/ +static int display_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = dev; + u16 width, height; + u16 virtual_width, virtual_height; + u32 rotate = FB_ROTATE_UR; + struct fb_info *fbi; + + if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) + return 0; + + if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= MCDE_NR_OF_DISPLAYS) + return 0; + + mcde_dss_get_native_resolution(ddev, &width, &height); + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY + if (ddev->id == PRIMARY_DISPLAY_ID) { + switch (CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE) { + case 0: + rotate = FB_ROTATE_UR; + break; + case 90: + rotate = FB_ROTATE_CW; + swap(width, height); + break; + case 180: + rotate = FB_ROTATE_UD; + break; + case 270: + rotate = FB_ROTATE_CCW; + swap(width, height); + break; + } + } +#endif + + virtual_width = width; + virtual_height = height * 2; + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC + if (ddev->id == PRIMARY_DISPLAY_ID) + virtual_height = height; +#endif + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC + if (ddev->id == SECONDARY_DISPLAY_ID) + virtual_height = height; +#endif + +#ifdef CONFIG_DISPLAY_AV8100_TRIPPLE_BUFFER + if (ddev->id == TERTIARY_DISPLAY_ID) + virtual_height = height * 3; +#endif + + if (ddev->id == TERTIARY_DISPLAY_ID) { +#ifdef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + hdmi_fb_onoff(ddev, 1, 0, 0); +#endif /* CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE */ + } else { + /* Create frame buffer */ + fbi = mcde_fb_create(ddev, + width, height, + virtual_width, virtual_height, + ddev->default_pixel_format, + rotate); + + if (IS_ERR(fbi)) + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", + ddev->name); + else + dev_info(&ddev->dev, "Framebuffer created (%s)\n", + ddev->name); + +#ifdef CONFIG_DISPDEV + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true) < 0) + dev_warn(&ddev->dev, + "Failed to create disp for display %s\n", + ddev->name); + else + dev_info(&ddev->dev, "Disp dev created for (%s)\n", + ddev->name); +#endif + } + + return 0; +} + +static struct notifier_block display_nb = { + .notifier_call = display_postregistered_callback, +}; + +/* +* This function is used to refresh the display (lcd, hdmi, tvout) with black +* when the framebuffer is registered. +* The main display will not be updated if startup graphics is displayed +* from u-boot. +*/ +#if defined(CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC) || \ + defined(CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC) +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + int i; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + var = info->var; + fix = info->fix; + + /* Apply overlay info */ + for (i = 0; i < mfb->num_ovlys; i++) { + struct mcde_overlay *ovly = mfb->ovlys[i]; + struct mcde_overlay_info ovly_info; + struct mcde_fb *mfb = to_mcde_fb(info); + memset(&ovly_info, 0, sizeof(ovly_info)); + ovly_info.paddr = fix.smem_start + + fix.line_length * var.yoffset; + if (ovly_info.paddr + fix.line_length * var.yres + > fix.smem_start + fix.smem_len) + ovly_info.paddr = fix.smem_start; + ovly_info.fmt = mfb->pix_fmt; + ovly_info.stride = fix.line_length; + ovly_info.w = var.xres; + ovly_info.h = var.yres; + ovly_info.dirty.w = var.xres; + ovly_info.dirty.h = var.yres; + (void) mcde_dss_apply_overlay(ovly, &ovly_info); + ret = mcde_dss_update_overlay(ovly); + if (ret) + break; + } + + return ret; +} +#else +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + if (mfb->id == 0 && display_initialized_during_boot) + goto out; + + var = info->var; + fix = info->fix; + var.yoffset = var.yoffset ? 0 : var.yres; + if (info->fbops->fb_pan_display) + ret = info->fbops->fb_pan_display(&var, info); +out: + return ret; +} +#endif + + +static struct notifier_block framebuffer_nb = { + .notifier_call = framebuffer_postregistered_callback, +}; + +int __init init_display_devices(void) +{ + int ret; + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC + struct i2c_adapter *i2c0; +#endif + + ret = fb_register_client(&framebuffer_nb); + if (ret) + pr_warning("Failed to register framebuffer notifier\n"); + + ret = mcde_dss_register_notifier(&display_nb); + if (ret) + pr_warning("Failed to register dss notifier\n"); + +#ifdef CONFIG_DISPLAY_GENERIC_PRIMARY + if (machine_is_hrefv60()) + generic_display0_pdata.reset_gpio = HREFV60_DISP1_RST_GPIO; + else + generic_display0_pdata.reset_gpio = EGPIO_PIN_15; + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC +#ifndef CONFIG_MACH_U8500_SNOWBALL + i2c0 = i2c_get_adapter(0); + if (i2c0) { + /* + * U8500-UIB has the TC35893 at 0x44 on I2C0, the + * ST-UIB has not. + */ + ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + i2c_put_adapter(i2c0); + + /* ret == 0 => U8500 UIB connected */ + generic_display0.synchronized_update = (ret == 0); + } +#else + generic_display0.synchronized_update = 0; +#endif +#endif + + if (display_initialized_during_boot) + generic_display0.power_mode = MCDE_DISPLAY_PM_STANDBY; + ret = mcde_display_device_register(&generic_display0); + if (ret) + pr_warning("Failed to register generic display device 0\n"); + displays[0] = &generic_display0; +#endif + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY + if (machine_is_hrefv60()) + generic_subdisplay_pdata.reset_gpio = HREFV60_DISP2_RST_GPIO; + else + generic_subdisplay_pdata.reset_gpio = EGPIO_PIN_14; + ret = mcde_display_device_register(&generic_subdisplay); + if (ret) + pr_warning("Failed to register generic sub display device\n"); + displays[1] = &generic_subdisplay; +#endif + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY + INIT_DELAYED_WORK_DEFERRABLE(&work_dispreg_hdmi, + delayed_work_dispreg_hdmi); + + schedule_delayed_work(&work_dispreg_hdmi, + msecs_to_jiffies(DISPREG_HDMI_DELAY)); +#endif +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY + ret = mcde_display_device_register(&tvout_ab8500_display); + if (ret) + pr_warning("Failed to register ab8500 tvout device\n"); + displays[2] = &tvout_ab8500_display; +#endif + + return ret; +} + +struct mcde_display_device *mcde_get_main_display(void) +{ +#if defined(CONFIG_DISPLAY_GENERIC_DSI_PRIMARY) + return &generic_display0; +#elif defined(CONFIG_DISPLAY_GENERIC_DSI_SECONDARY) + return &generic_subdisplay; +#elif defined(CONFIG_DISPLAY_AV8100_TERTIARY) + return &av8100_hdmi; +#elif defined(CONFIG_DISPLAY_AB8500_TERTIARY) + return &tvout_ab8500_display; +#else + return NULL; +#endif +} +EXPORT_SYMBOL(mcde_get_main_display); + +void hdmi_fb_onoff(struct mcde_display_device *ddev, + bool enable, u8 cea, u8 vesa_cea_nr) +{ + struct fb_info *fbi; + u16 w, h; + u16 vw, vh; + u32 rotate = FB_ROTATE_UR; + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(&ddev->dev, "%s\n", __func__); + dev_dbg(&ddev->dev, "en:%d cea:%d nr:%d\n", enable, cea, vesa_cea_nr); + + if (enable) { + if (ddev->enabled) { + dev_dbg(&ddev->dev, "Display is already enabled.\n"); + return; + } + + /* Create fb */ + if (ddev->fbi == NULL) { + /* Note: change when dynamic buffering is available */ + int buffering = 2; + + /* Get default values */ + mcde_dss_get_native_resolution(ddev, &w, &h); + vw = w; + vh = h * buffering; + + if (vesa_cea_nr != 0) + ddev->ceanr_convert(ddev, cea, vesa_cea_nr, + buffering, &w, &h, &vw, &vh); + + fbi = mcde_fb_create(ddev, w, h, vw, vh, + ddev->default_pixel_format, rotate); + + if (IS_ERR(fbi)) { + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", + ddev->name); + goto hdmi_fb_onoff_end; + } else { + dev_info(&ddev->dev, + "Framebuffer created (%s)\n", + ddev->name); + } + driver_data->fbdevname = (char *)dev_name(fbi->dev); + +#ifdef CONFIG_DISPDEV + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true) < 0) + dev_warn(&ddev->dev, + "Failed to create disp for %s\n", + ddev->name); + else + dev_info(&ddev->dev, + "Disp dev created for (%s)\n", + ddev->name); +#endif /* CONFIG_DISPDEV */ + } + } else { + if (!ddev->enabled) { + dev_dbg(&ddev->dev, "Display %s is already disabled.\n", + ddev->name); + return; + } + +#ifdef CONFIG_DISPDEV + dispdev_destroy(ddev); +#endif /* CONFIG_DISPDEV */ + mcde_fb_destroy(ddev); + } + +hdmi_fb_onoff_end: + return; +} +EXPORT_SYMBOL(hdmi_fb_onoff); + + +module_init(init_display_devices); + +#endif diff --git a/arch/arm/mach-ux500/board-mop500-mcde.h b/arch/arm/mach-ux500/board-mop500-mcde.h new file mode 100644 index 00000000000..38094b81b34 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-mcde.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * + * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com> for ST-Ericsson + * + * MOP500 board specific initialization for regulators + */ + +#ifndef __BOARD_MOP500_MCDE_H +#define __BOARD_MOP500_MCDE_H + +#include <video/mcde_display.h> + +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY +extern struct mcde_display_device tvout_ab8500_display; +#endif + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +extern struct mcde_display_device av8100_hdmi; +#endif + +#endif /* __BOARD_MOP500_MCDE_H */ diff --git a/arch/arm/mach-ux500/board-mop500-mmio.c b/arch/arm/mach-ux500/board-mop500-mmio.c new file mode 100644 index 00000000000..3f3d27d3cee --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-mmio.c @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2011 ST-Ericsson + * Author: Joakim Axelsson <joakim.axelsson@stericsson.com> for ST-Ericsson + * Author: Rajat Verma <rajat.verma@stericsson.com> for ST-Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/mmio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/vmalloc.h> +#include <plat/pincfg.h> +#include <mach/gpio.h> +#include <mach/devices.h> +#include "pins-db8500.h" +#include "pins.h" +#include "board-mop500.h" + +static pin_cfg_t i2c2_pins[] = { + GPIO8_I2C2_SDA, + GPIO9_I2C2_SCL +}; +static pin_cfg_t ipi2c_pins[] = { + GPIO8_IPI2C_SDA, + GPIO9_IPI2C_SCL +}; +static pin_cfg_t i2c_disable_pins[] = { + GPIO8_GPIO, + GPIO9_GPIO +}; +static pin_cfg_t xshutdown_host[] = { + GPIO141_GPIO, + GPIO142_GPIO +}; +static pin_cfg_t xshutdown_fw[] = { + GPIO141_IP_GPIO2, + GPIO142_IP_GPIO3 +}; +static pin_cfg_t xshutdown_disable[] = { + GPIO141_GPIO, + GPIO142_GPIO +}; + +struct mmio_board_data{ + int number_of_regulators; + struct regulator **mmio_regulators; + /* Pin configs */ + int xenon_charge; + struct mmio_gpio xshutdown_pins[CAMERA_SLOT_END]; + /* Internal clocks */ + struct clk *clk_ptr_bml; + struct clk *clk_ptr_ipi2c; + /* External clocks */ + struct clk *clk_ptr_ext[CAMERA_SLOT_END]; +}; + +/* Fill names of regulators required for powering up the + * camera sensor in below array */ +static char *regulator_names[] = {"v-mmio-camera" , "v-ana"}; + +/* This function is used to translate the physical GPIO used for reset GPIO + * to logical IPGPIO that needs to be communicated to Firmware. so that + * firmware can control reset GPIO of a RAW Bayer sensor */ +static int mmio_get_ipgpio(struct mmio_platform_data *pdata, int gpio, + int *ip_gpio) +{ + int err = 0; + dev_dbg(pdata->dev, "%s() : IPGPIO requested for %d", __func__, gpio); + switch (gpio) { + case 67: + case 140: + *ip_gpio = 7; + break; + case 5: + case 66: + *ip_gpio = 6; + break; + case 81: + case 65: + *ip_gpio = 5; + break; + case 80: + case 64: + *ip_gpio = 4; + break; + case 10: + case 79: + case 142: + *ip_gpio = 3; + break; + case 11: + case 78: + case 141: + *ip_gpio = 2; + break; + case 7: + case 150: + *ip_gpio = 1; + break; + case 6: + case 149: + *ip_gpio = 0; + break; + default: + *ip_gpio = -1; + err = -1; + break; + } + return err; +} + +static int mmio_clock_init(struct mmio_platform_data *pdata) +{ + int err; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + + extra->clk_ptr_bml = clk_get_sys("bml", NULL); + if (IS_ERR(extra->clk_ptr_bml)) { + err = PTR_ERR(extra->clk_ptr_bml); + dev_err(pdata->dev, "Error %d getting clock 'bml'\n", err); + goto err_bml_clk; + } + extra->clk_ptr_ipi2c = clk_get_sys("ipi2", NULL); + if (IS_ERR(extra->clk_ptr_ipi2c)) { + err = PTR_ERR(extra->clk_ptr_ipi2c); + dev_err(pdata->dev, "Error %d getting clock 'ipi2'\n", err); + goto err_ipi2c_clk; + } + extra->clk_ptr_ext[PRIMARY_CAMERA] = clk_get_sys("pri-cam", NULL); + if (IS_ERR(extra->clk_ptr_ext[PRIMARY_CAMERA])) { + err = PTR_ERR(extra->clk_ptr_ext[PRIMARY_CAMERA]); + dev_err(pdata->dev, "Error %d getting clock 'pri-cam'\n", err); + goto err_pri_ext_clk; + } + extra->clk_ptr_ext[SECONDARY_CAMERA] = clk_get_sys("sec-cam", NULL); + if (IS_ERR(extra->clk_ptr_ext[SECONDARY_CAMERA])) { + err = PTR_ERR(extra->clk_ptr_ext[SECONDARY_CAMERA]); + dev_err(pdata->dev, "Error %d getting clock 'sec-cam'\n", err); + goto err_sec_ext_clk; + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_sec_ext_clk: + clk_put(extra->clk_ptr_ext[PRIMARY_CAMERA]); +err_pri_ext_clk: + clk_put(extra->clk_ptr_ipi2c); +err_ipi2c_clk: + clk_put(extra->clk_ptr_bml); +err_bml_clk: + return err; +} +static void mmio_clock_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + clk_put(extra->clk_ptr_bml); + clk_put(extra->clk_ptr_ipi2c); + clk_put(extra->clk_ptr_ext[PRIMARY_CAMERA]); + clk_put(extra->clk_ptr_ext[SECONDARY_CAMERA]); +} + + +static int mmio_pin_cfg_init(struct mmio_platform_data *pdata) +{ + int err; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + + extra->xshutdown_pins[PRIMARY_CAMERA].gpio = XSHUTDOWN_PRIMARY_SENSOR; + extra->xshutdown_pins[PRIMARY_CAMERA].active_high = 0; + extra->xshutdown_pins[PRIMARY_CAMERA].udelay = 500; + + extra->xshutdown_pins[SECONDARY_CAMERA].active_high = 0; + extra->xshutdown_pins[SECONDARY_CAMERA].udelay = 500; + + /* Update GPIO mappings according to board */ + if (machine_is_hrefv60()) { + extra->xenon_charge = HREFV60_MMIO_XENON_CHARGE; + xshutdown_host[SECONDARY_CAMERA] = GPIO140_GPIO; + xshutdown_fw[SECONDARY_CAMERA] = GPIO140_IP_GPIO7; + xshutdown_disable[SECONDARY_CAMERA] = GPIO140_GPIO; + extra->xshutdown_pins[SECONDARY_CAMERA].gpio = 140; + } else { + extra->xenon_charge = EGPIO_PIN_5; + xshutdown_host[SECONDARY_CAMERA] = GPIO142_GPIO; + xshutdown_fw[SECONDARY_CAMERA] = GPIO142_IP_GPIO3; + xshutdown_disable[SECONDARY_CAMERA] = GPIO142_GPIO; + extra->xshutdown_pins[SECONDARY_CAMERA].gpio = 142; + } + /* Setup Xenon Charge */ + err = gpio_request(extra->xenon_charge, "xenon charge"); + if (err) { + dev_err(pdata->dev, "Error %d while requesting xenon charge\n", + err); + goto err_xenon_gpio_req; + } + err = gpio_direction_output(extra->xenon_charge, 0); + if (err) { + dev_err(pdata->dev, "Error %d while setting xenon charge in" + "output mode\n", err); + goto err_xenon_gpio_set_dir; + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_xenon_gpio_set_dir: + gpio_free(extra->xenon_charge); +err_xenon_gpio_req: + return err; +} + +static void mmio_pin_cfg_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + gpio_free(extra->xenon_charge); +} + +/* For now, both sensors on HREF have some power up sequence. If different + * sequences are needed for primary and secondary sensors, it can be + * implemented easily. Just use camera_slot field of mmio_platform_data + * to determine which camera needs to be powered up */ +static int mmio_power_init(struct mmio_platform_data *pdata) +{ + int err = 0, i = 0; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + extra->number_of_regulators = sizeof(regulator_names)/ + sizeof(regulator_names[0]); + extra->mmio_regulators = + kzalloc(sizeof(struct regulator *) * extra->number_of_regulators, + GFP_KERNEL); + if (!extra->mmio_regulators) { + dev_err(pdata->dev , "Error while allocating memory for mmio" + "regulators\n"); + err = -ENOMEM; + goto err_no_mem_reg; + } + for (i = 0; i < + extra->number_of_regulators; i++) { + extra->mmio_regulators[i] = + regulator_get(pdata->dev, regulator_names[i]); + if (IS_ERR(extra->mmio_regulators[i])) { + err = PTR_ERR(extra->mmio_regulators[i]); + dev_err(pdata->dev , "Error %d getting regulator '%s'" + "\n", err, regulator_names[i]); + goto err_regulator; + } + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_regulator: + /* Return regulators we have already requested */ + while (i--) + regulator_put(extra->mmio_regulators[i]); + kfree(extra->mmio_regulators); +err_no_mem_reg: + return err; +} +static void mmio_power_exit(struct mmio_platform_data *pdata) +{ + int i = 0; + struct mmio_board_data *extra = pdata->extra;; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + for (i = 0; i < extra->number_of_regulators; i++) + regulator_put(extra->mmio_regulators[i]); + kfree(extra->mmio_regulators); +} + +static int mmio_platform_init(struct mmio_platform_data *pdata) +{ + int err = 0; + struct mmio_board_data *extra = NULL; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* Alloc memory for our own extra data */ + extra = kzalloc(sizeof(struct mmio_board_data), GFP_KERNEL); + if (!extra) { + dev_err(pdata->dev, "%s: memory alloc failed for " + "mmio_board_data\n", __func__); + err = -ENOMEM; + goto err_no_mem_extra; + } + /* Hook the data for other callbacks to use */ + pdata->extra = extra; + + pdata->camera_slot = -1; + + err = mmio_power_init(pdata); + if (err) + goto err_regulator; + err = mmio_clock_init(pdata); + if (err) + goto err_clock; + err = mmio_pin_cfg_init(pdata); + if (err) + goto err_pin_cfg; + /* Store logical IPGPIO for physical reset GPIOs used */ + err = mmio_get_ipgpio(pdata, + extra->xshutdown_pins[PRIMARY_CAMERA].gpio, + &(pdata->reset_ipgpio[PRIMARY_CAMERA])); + if (err) { + dev_err(pdata->dev, "Error getting ipgpio for pri cam\n"); + goto err_ipgpio; + } + err = mmio_get_ipgpio(pdata, + extra->xshutdown_pins[SECONDARY_CAMERA].gpio, + &(pdata->reset_ipgpio[SECONDARY_CAMERA])); + if (err) { + dev_err(pdata->dev, "Error getting ipgpio for sec cam\n"); + goto err_ipgpio; + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_ipgpio: + mmio_pin_cfg_exit(pdata); +err_pin_cfg: + mmio_clock_exit(pdata); +err_clock: + mmio_power_exit(pdata); +err_regulator: + kfree(extra); +err_no_mem_extra: + return err; +} +static void mmio_platform_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + mmio_power_exit(pdata); + mmio_clock_exit(pdata); + mmio_pin_cfg_exit(pdata); + kfree(extra); + pdata->extra = NULL; +} + +static int mmio_power_enable(struct mmio_platform_data *pdata) +{ + int err = 0, i = 0; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* Enable the regulators */ + for (i = 0; i < extra->number_of_regulators; i++) { + err = regulator_enable(extra->mmio_regulators[i]); + if (IS_ERR(extra->mmio_regulators[i])) { + err = PTR_ERR(extra->mmio_regulators[i]); + dev_err(pdata->dev , "Error %d enabling regulator '%s'" + "\n", err, regulator_names[i]); + goto err_regulator; + } + } + /* Set Xenon Charge */ + gpio_set_value(extra->xenon_charge, 1); + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_regulator: + /* Disable regulators we already enabled */ + while (i--) + regulator_disable(extra->mmio_regulators[i]); + return err; +} + +static void mmio_power_disable(struct mmio_platform_data *pdata) +{ + int i; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* Disable the regulators */ + for (i = 0; i < extra->number_of_regulators; i++) + regulator_disable(extra->mmio_regulators[i]); + /* Disable Xenon Charge */ + gpio_set_value(extra->xenon_charge, 0); +} +static int mmio_clock_enable(struct mmio_platform_data *pdata) +{ + int err = 0; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* Enable internal clocks */ + err = clk_enable(extra->clk_ptr_bml); + if (err) { + dev_err(pdata->dev, "Error activating bml clock %d\n", err); + goto err_bml_clk; + } + err = clk_enable(extra->clk_ptr_ipi2c); + if (err) { + dev_err(pdata->dev, "Error activating i2c2 clock %d\n", err); + goto err_ipi2c_clk; + } + /* Enable appropriate external clock */ + err = clk_enable(extra->clk_ptr_ext[pdata->camera_slot]); + if (err) { + dev_err(pdata->dev, "Error activating clock for sensor %d, err" + "%d\n", pdata->camera_slot, err); + goto err_ext_clk; + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_ext_clk: + clk_disable(extra->clk_ptr_ipi2c); +err_ipi2c_clk: + clk_disable(extra->clk_ptr_bml); +err_bml_clk: + return err; +} + +static void mmio_clock_disable(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + clk_disable(extra->clk_ptr_bml); + clk_disable(extra->clk_ptr_ipi2c); + clk_disable(extra->clk_ptr_ext[pdata->camera_slot]); +} + + +static int mmio_config_xshutdown_pins(struct mmio_platform_data *pdata, + enum mmio_select_xshutdown_t select, + int is_active_high) +{ + int err = 0; + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + switch (select) { + case MMIO_ENABLE_XSHUTDOWN_HOST: + extra->xshutdown_pins[pdata->camera_slot].active_high = + is_active_high; + err = nmk_config_pin(xshutdown_host[pdata->camera_slot] | + (is_active_high ? PIN_OUTPUT_LOW : PIN_OUTPUT_HIGH), + 0); + break; + case MMIO_ENABLE_XSHUTDOWN_FW: + err = nmk_config_pin(xshutdown_fw[pdata->camera_slot], 0); + break; + case MMIO_DISABLE_XSHUTDOWN: + err = nmk_config_pin(xshutdown_disable[pdata->camera_slot], + 0); + break; + default: + break; + } + if (err) + dev_dbg(pdata->dev , "Error configuring xshutdown, err = %d\n", + err); + return err; +} +static void mmio_set_xshutdown(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + gpio_set_value(extra->xshutdown_pins[pdata->camera_slot].gpio , + (extra->xshutdown_pins[pdata->camera_slot].active_high ? 1 : + 0)); + udelay(extra->xshutdown_pins[pdata->camera_slot].udelay); +} +static int mmio_config_i2c_pins(struct mmio_platform_data *pdata, + enum mmio_select_i2c_t select) +{ + int err = 0; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + switch (select) { + case MMIO_ACTIVATE_I2C_HOST: + err = nmk_config_pins(i2c2_pins, ARRAY_SIZE(i2c2_pins)); + break; + case MMIO_ACTIVATE_IPI2C2: + err = nmk_config_pins(ipi2c_pins, ARRAY_SIZE(ipi2c_pins)); + break; + case MMIO_DEACTIVATE_I2C: + err = nmk_config_pins(i2c_disable_pins, + ARRAY_SIZE(i2c_disable_pins)); + break; + default: + break; + } + + return err; +} +static struct mmio_platform_data mmio_config = { + .platform_init = mmio_platform_init, + .platform_exit = mmio_platform_exit, + .power_enable = mmio_power_enable, + .power_disable = mmio_power_disable, + .clock_enable = mmio_clock_enable, + .clock_disable = mmio_clock_disable, + .config_i2c_pins = mmio_config_i2c_pins, + .config_xshutdown_pins = mmio_config_xshutdown_pins, + .set_xshutdown = mmio_set_xshutdown +}; + +struct platform_device ux500_mmio_device = { + .name = MMIO_NAME, + .id = -1, + .dev = { + .platform_data = &mmio_config, + } +}; diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c new file mode 100644 index 00000000000..e90dead020b --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-msp.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/platform_device.h> +#include <linux/i2s/i2s.h> +#include <linux/init.h> +#include <linux/gpio.h> + +#include <plat/ste_dma40.h> +#include <plat/pincfg.h> + +#include <mach/devices.h> +#include <mach/ste-dma40-db8500.h> +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/msp.h> + +#include "board-mop500.h" +#include "devices-db8500.h" +#include "pins-db8500.h" + +/* MSP1/3 Tx/Rx usage protection */ +static DEFINE_SPINLOCK(msp_rxtx_lock); + +/* Reference Count */ +static int msp_rxtx_ref; + +static pin_cfg_t mop500_msp1_pins_init[] = { + GPIO33_MSP1_TXD | PIN_OUTPUT_LOW | PIN_SLPM_WAKEUP_DISABLE, + GPIO34_MSP1_TFS | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_DISABLE, + GPIO35_MSP1_TCK | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_DISABLE, + GPIO36_MSP1_RXD | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_DISABLE, +}; + +static pin_cfg_t mop500_msp1_pins_exit[] = { + GPIO33_MSP1_TXD | PIN_OUTPUT_LOW | PIN_SLPM_WAKEUP_ENABLE, + GPIO34_MSP1_TFS | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_ENABLE, + GPIO35_MSP1_TCK | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_ENABLE, + GPIO36_MSP1_RXD | PIN_INPUT_NOPULL | PIN_SLPM_WAKEUP_ENABLE, +}; + +int msp13_i2s_init(void) +{ + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&msp_rxtx_lock, flags); + if (msp_rxtx_ref == 0) + retval = nmk_config_pins( + ARRAY_AND_SIZE(mop500_msp1_pins_init)); + if (!retval) + msp_rxtx_ref++; + spin_unlock_irqrestore(&msp_rxtx_lock, flags); + + return retval; +} + +int msp13_i2s_exit(void) +{ + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&msp_rxtx_lock, flags); + WARN_ON(!msp_rxtx_ref); + msp_rxtx_ref--; + if (msp_rxtx_ref == 0) + retval = nmk_config_pins_sleep( + ARRAY_AND_SIZE(mop500_msp1_pins_exit)); + spin_unlock_irqrestore(&msp_rxtx_lock, flags); + + return retval; +} + +static struct stedma40_chan_cfg msp0_dma_rx = { + .high_priority = true, + .dir = STEDMA40_PERIPH_TO_MEM, + + .src_dev_type = DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct stedma40_chan_cfg msp0_dma_tx = { + .high_priority = true, + .dir = STEDMA40_MEM_TO_PERIPH, + + .src_dev_type = STEDMA40_DEV_DST_MEMORY, + .dst_dev_type = DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct msp_i2s_platform_data msp0_platform_data = { + .id = MSP_0_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp0_dma_rx, + .msp_i2s_dma_tx = &msp0_dma_tx, +}; + +static struct stedma40_chan_cfg msp1_dma_rx = { + .high_priority = true, + .dir = STEDMA40_PERIPH_TO_MEM, + + .src_dev_type = DB8500_DMA_DEV30_MSP1_RX, /* v2: MSP3 RX */ + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct stedma40_chan_cfg msp1_dma_tx = { + .high_priority = true, + .dir = STEDMA40_MEM_TO_PERIPH, + + .src_dev_type = STEDMA40_DEV_DST_MEMORY, + .dst_dev_type = DB8500_DMA_DEV30_MSP1_TX, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct msp_i2s_platform_data msp1_platform_data = { + .id = MSP_1_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp1_dma_rx, + .msp_i2s_dma_tx = &msp1_dma_tx, + .msp_i2s_init = msp13_i2s_init, + .msp_i2s_exit = msp13_i2s_exit, +}; + +static struct stedma40_chan_cfg msp2_dma_rx = { + .high_priority = true, + .dir = STEDMA40_PERIPH_TO_MEM, + + .src_dev_type = DB8500_DMA_DEV14_MSP2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct stedma40_chan_cfg msp2_dma_tx = { + .high_priority = true, + .dir = STEDMA40_MEM_TO_PERIPH, + + .src_dev_type = STEDMA40_DEV_DST_MEMORY, + .dst_dev_type = DB8500_DMA_DEV14_MSP2_TX, + + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + + /* data_width is set during configuration */ +}; + +static struct msp_i2s_platform_data msp2_platform_data = { + .id = MSP_2_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp2_dma_rx, + .msp_i2s_dma_tx = &msp2_dma_tx, +}; + +static struct msp_i2s_platform_data msp3_platform_data = { + .id = MSP_3_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp1_dma_rx, + .msp_i2s_dma_tx = NULL, + .msp_i2s_init = msp13_i2s_init, + .msp_i2s_exit = msp13_i2s_exit, +}; + +static struct i2s_board_info stm_i2s_board_info[] __initdata = { + { + .modalias = "i2s_device.0", + .id = MSP_0_CONTROLLER - 1, + .chip_select = 0, + }, + { + .modalias = "i2s_device.1", + .id = MSP_1_CONTROLLER - 1, + .chip_select = 1, + }, + { + .modalias = "i2s_device.2", + .id = MSP_2_CONTROLLER - 1, + .chip_select = 2, + }, + { + .modalias = "i2s_device.3", + .id = MSP_3_CONTROLLER - 1, + .chip_select = 3, + }, +}; + +static void __init mop500_msp_fixup(void) +{ + if (cpu_is_u8500ed() || cpu_is_u8500v1()) + return; + + /* DMA Rx is moved to MSP3 on DB8500v2 */ + msp1_platform_data.msp_i2s_dma_rx = NULL; + + /* MSP2 DMA doesn't work with PSIZE == 4 on DB8500v2 */ + msp2_dma_rx.src_info.psize = STEDMA40_PSIZE_LOG_1; + msp2_dma_rx.dst_info.psize = STEDMA40_PSIZE_LOG_1; +} + +void __init mop500_msp_init(void) +{ + mop500_msp_fixup(); + + db8500_add_msp0_i2s(&msp0_platform_data); + db8500_add_msp1_i2s(&msp1_platform_data); + db8500_add_msp2_i2s(&msp2_platform_data); + + if (cpu_is_u8500v2()) + db8500_add_msp3_i2s(&msp3_platform_data); + + i2s_register_board_info(stm_i2s_board_info, + ARRAY_SIZE(stm_i2s_board_info)); +} diff --git a/arch/arm/mach-ux500/board-mop500-nuib.c b/arch/arm/mach-ux500/board-mop500-nuib.c new file mode 100644 index 00000000000..2f1e733afe3 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-nuib.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 ST-Ericsson SA + * + * License terms:GNU General Public License (GPL) version 2 + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input/synaptics_i2c_rmi4.h> + +#include "board-mop500.h" + +/* Descriptor structure. + * Describes the number of i2c devices on the bus that speak RMI. + */ +static struct synaptics_rmi4_platform_data rmi4_i2c_dev_platformdata = { + .irq_number = GPIO_TO_IRQ(84), + .irq_type = (IRQF_TRIGGER_FALLING | IRQF_SHARED), +#if CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE == 270 + .x_flip = true, + .y_flip = false, +#else + .x_flip = false, + .y_flip = true, +#endif + .regulator_en = true, +}; + +static struct i2c_board_info __initdata u8500_i2c3_devices_nuib[] = { + { + /* Touschscreen */ + I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B), + .platform_data = &rmi4_i2c_dev_platformdata, + }, +}; + +void __init mop500_nuib_init(void) +{ + i2c_register_board_info(3, u8500_i2c3_devices_nuib, + ARRAY_SIZE(u8500_i2c3_devices_nuib)); +} diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c new file mode 100644 index 00000000000..bfe6e1f1fc6 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -0,0 +1,731 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/string.h> + +#include <plat/pincfg.h> +#include <plat/gpio.h> + +#include <mach/hardware.h> +#include <mach/suspend.h> + +#include "pins-db8500.h" +#include "pins.h" + +enum custom_pin_cfg_t { + PINS_FOR_DEFAULT, + PINS_FOR_U9500_21, +}; + +static enum custom_pin_cfg_t pinsfor = PINS_FOR_DEFAULT; + +static pin_cfg_t mop500_pins_common[] = { + /* MSP0 */ + GPIO12_MSP0_TXD, + GPIO13_MSP0_TFS, + GPIO14_MSP0_TCK, + GPIO15_MSP0_RXD, + + /* MSP2: HDMI */ + GPIO193_MSP2_TXD, + GPIO194_MSP2_TCK, + GPIO195_MSP2_TFS, + GPIO196_MSP2_RXD | PIN_OUTPUT_LOW, + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* Touch screen INTERFACE */ + GPIO84_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT1 */ +#endif + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* STMPE1601/tc35893 keypad IRQ */ + GPIO218_GPIO | PIN_INPUT_PULLUP, +#endif + + /* UART */ + /* uart-0 pins gpio configuration should be + * kept intact to prevent glitch in tx line + * when tty dev is opened. Later these pins + * are configured to uart mop500_pins_uart0 + * + * It will be replaced with uart configuration + * once the issue is solved. + */ + GPIO0_GPIO | PIN_INPUT_PULLUP, + GPIO1_GPIO | PIN_OUTPUT_HIGH, + GPIO2_GPIO | PIN_INPUT_PULLUP, + GPIO3_GPIO | PIN_OUTPUT_LOW, + + GPIO29_U2_RXD | PIN_INPUT_PULLUP, + GPIO30_U2_TXD | PIN_OUTPUT_HIGH, + GPIO31_U2_CTSn | PIN_INPUT_PULLUP, + GPIO32_U2_RTSn | PIN_OUTPUT_HIGH, + + /* USB */ + GPIO256_USB_NXT, + GPIO257_USB_STP | PIN_OUTPUT_HIGH, + GPIO258_USB_XCLK, + GPIO259_USB_DIR, + GPIO260_USB_DAT7, + GPIO261_USB_DAT6, + GPIO262_USB_DAT5, + GPIO263_USB_DAT4, + GPIO264_USB_DAT3, + GPIO265_USB_DAT2, + GPIO266_USB_DAT1, + GPIO267_USB_DAT0, + +/* May not be in snowball #ifndef CONFIG_MACH_U8500_SNOWBALL */ + /* Display & HDMI HW sync */ + GPIO68_LCD_VSI0 | PIN_INPUT_PULLUP, + GPIO69_LCD_VSI1 | PIN_INPUT_PULLUP, + + /* HSI */ + GPIO219_HSIR_FLA0, + GPIO220_HSIR_DAT0, + GPIO221_HSIR_RDY0, + GPIO222_HSIT_FLA0, + GPIO223_HSIT_DAT0, + GPIO224_HSIT_RDY0, + GPIO225_GPIO | PIN_INPUT_PULLDOWN, /* CA_WAKE0 */ + GPIO226_GPIO | PIN_OUTPUT_LOW, /* WLAN_PMU_EN / AC_WAKE0 */ +/* May not be in snowball #endif */ + +#ifdef CONFIG_MACH_U8500_SNOWBALL + /* SSP0, to AB8500 */ + GPIO143_SSP0_CLK, + GPIO144_SSP0_FRM, + GPIO145_SSP0_RXD | PIN_PULL_DOWN, + GPIO146_SSP0_TXD, +#endif + +#ifdef CONFIG_MACH_U8500_SNOWBALL + /* MMC2: LAN */ + GPIO86_SM_ADQ0, + GPIO87_SM_ADQ1, + GPIO88_SM_ADQ2, + GPIO89_SM_ADQ3, + GPIO90_SM_ADQ4, + GPIO91_SM_ADQ5, + GPIO92_SM_ADQ6, + GPIO93_SM_ADQ7, + + GPIO94_SM_ADVn, + GPIO95_SM_CS0n, + GPIO96_SM_OEn, + GPIO97_SM_WEn, + + GPIO128_SM_CKO, + GPIO130_SM_FBCLK, + GPIO131_SM_ADQ8, + GPIO132_SM_ADQ9, + GPIO133_SM_ADQ10, + GPIO134_SM_ADQ11, + GPIO135_SM_ADQ12, + GPIO136_SM_ADQ13, + GPIO137_SM_ADQ14, + GPIO138_SM_ADQ15, + + /* RSTn_LAN */ + GPIO141_GPIO | PIN_OUTPUT_HIGH, + GPIO161_GPIO | PIN_OUTPUT_LOW, /* WLAN_PMU_EN */ +#endif + + +}; + +static pin_cfg_t mop500_pins_default[] = { +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* XENON Flashgun INTERFACE */ + GPIO6_IP_GPIO0 | PIN_INPUT_PULLUP,/* XENON_FLASH_ID */ + GPIO7_IP_GPIO1 | PIN_INPUT_PULLUP,/* XENON_READY */ + +#endif + GPIO217_GPIO | PIN_INPUT_PULLUP, /* TC35892 IRQ */ + + /* sdi0 (removable MMC/SD/SDIO cards) not handled by pm_runtime */ + GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH, +}; + +static pin_cfg_t mop500_pins_hrefv60[] = { + /* WLAN */ + GPIO4_GPIO | PIN_INPUT_PULLUP,/* WLAN_IRQ */ + GPIO85_GPIO | PIN_OUTPUT_LOW,/* WLAN_ENA */ + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* XENON Flashgun INTERFACE */ + GPIO6_IP_GPIO0 | PIN_INPUT_PULLUP,/* XENON_FLASH_ID */ + GPIO7_IP_GPIO1 | PIN_INPUT_PULLUP,/* XENON_READY */ +#endif + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* Assistant LED INTERFACE */ + GPIO21_GPIO | PIN_OUTPUT_LOW, /* XENON_EN1 */ + GPIO64_IP_GPIO4 | PIN_OUTPUT_LOW, /* XENON_EN2 */ +#endif + + /* Magnetometer */ + GPIO31_GPIO | PIN_INPUT_PULLUP, /* magnetometer_INT */ + GPIO32_GPIO | PIN_INPUT_PULLDOWN, /* Magnetometer DRDY */ + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* Display Interface */ + GPIO65_GPIO | PIN_OUTPUT_LOW, /* DISP1 RST */ + GPIO66_GPIO | PIN_OUTPUT_LOW, /* DISP2 RST */ +#endif + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* Touch screen INTERFACE */ + GPIO143_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST1 */ + + /* Touch screen INTERFACE 2 */ + GPIO67_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT2 */ + GPIO146_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST2 */ + + /* ETM_PTM_TRACE INTERFACE */ + GPIO70_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA23 */ + GPIO71_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA22 */ + GPIO72_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA21 */ + GPIO73_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA20 */ + GPIO74_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA19 */ + + /* NAHJ INTERFACE */ + GPIO76_GPIO | PIN_OUTPUT_LOW,/* NAHJ_CTRL */ +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO216_GPIO | PIN_OUTPUT_HIGH,/* NAHJ_CTRL_INV */ +#endif + + /* NFC INTERFACE */ + GPIO77_GPIO | PIN_OUTPUT_LOW, /* NFC_ENA */ + GPIO144_GPIO | PIN_INPUT_PULLDOWN, /* NFC_IRQ */ + GPIO142_GPIO | PIN_OUTPUT_LOW, /* NFC_RESET */ + + /* Keyboard MATRIX INTERFACE */ + GPIO90_MC5_CMD | PIN_OUTPUT_LOW, /* KP_O_1 */ + GPIO87_MC5_DAT1 | PIN_OUTPUT_LOW, /* KP_O_2 */ + GPIO86_MC5_DAT0 | PIN_OUTPUT_LOW, /* KP_O_3 */ + GPIO96_KP_O6 | PIN_OUTPUT_LOW, /* KP_O_6 */ + GPIO94_KP_O7 | PIN_OUTPUT_LOW, /* KP_O_7 */ + GPIO93_MC5_DAT4 | PIN_INPUT_PULLUP, /* KP_I_0 */ + GPIO89_MC5_DAT3 | PIN_INPUT_PULLUP, /* KP_I_2 */ + GPIO88_MC5_DAT2 | PIN_INPUT_PULLUP, /* KP_I_3 */ + GPIO91_GPIO | PIN_INPUT_PULLUP, /* FORCE_SENSING_INT */ + GPIO92_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_RST */ + GPIO97_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_WU */ + + /* DiPro Sensor Interface */ + GPIO139_GPIO | PIN_INPUT_PULLUP, /* DIPRO_INT */ + + /* HAL SWITCH INTERFACE */ + GPIO145_GPIO | PIN_INPUT_PULLDOWN,/* HAL_SW */ +#endif + + /* Audio Amplifier Interface */ + GPIO149_GPIO | PIN_OUTPUT_HIGH, /* VAUDIO_HF_EN, enable MAX8968 */ + + /* GBF INTERFACE */ + GPIO171_GPIO | PIN_OUTPUT_LOW, /* GBF_ENA_RESET */ + +#ifdef CONFIG_MACH_U8500_SNOWBALL + /* WLAN/GBF */ + GPIO215_GPIO | PIN_OUTPUT_LOW, /* WLAN_ENABLE */ + GPIO216_GPIO | PIN_INPUT_PULLUP, /* WLAN_IRQ */ + GPIO171_GPIO | PIN_OUTPUT_HIGH, /* GBF_ENA_RESET */ +#endif + + + /* MSP : HDTV INTERFACE */ + GPIO192_GPIO | PIN_INPUT_PULLDOWN, + + /* ACCELEROMETER_INTERFACE */ + GPIO82_GPIO | PIN_INPUT_PULLUP, /* ACC_INT1 */ + GPIO83_GPIO | PIN_INPUT_PULLUP, /* ACC_INT2 */ + +#ifndef CONFIG_MACH_U8500_SNOWBALL + /* Proximity Sensor */ + GPIO217_GPIO | PIN_INPUT_PULLUP, +#endif + /* SD card detect */ + GPIO95_GPIO | PIN_INPUT_PULLUP, +}; + +static pin_cfg_t u9500_21_pins[] = { + GPIO4_U1_RXD | PIN_INPUT_PULLUP, + GPIO5_U1_TXD | PIN_OUTPUT_HIGH, +}; + +static UX500_PINS(mop500_pins_uart0, + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH, +); + +/* + * I2C + */ + +static UX500_PINS(mop500_pins_i2c0, +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO147_I2C0_SCL, + GPIO148_I2C0_SDA, +#endif +); + +static UX500_PINS(mop500_pins_i2c1, + GPIO16_I2C1_SCL, + GPIO17_I2C1_SDA, +); + +static UX500_PINS(mop500_pins_i2c2, + GPIO10_I2C2_SDA, + GPIO11_I2C2_SCL, +); + +static UX500_PINS(mop500_pins_i2c3, + GPIO229_I2C3_SDA, + GPIO230_I2C3_SCL, +); + +static UX500_PINS(mop500_pins_mcde_dpi, +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO64_LCDB_DE, + GPIO65_LCDB_HSO, + GPIO66_LCDB_VSO, + GPIO67_LCDB_CLK, + GPIO70_LCD_D0, + GPIO71_LCD_D1, + GPIO72_LCD_D2, + GPIO73_LCD_D3, + GPIO74_LCD_D4, + GPIO75_LCD_D5, + GPIO76_LCD_D6, + GPIO77_LCD_D7, + GPIO153_LCD_D24, + GPIO154_LCD_D25, + GPIO155_LCD_D26, + GPIO156_LCD_D27, + GPIO157_LCD_D28, + GPIO158_LCD_D29, + GPIO159_LCD_D30, + GPIO160_LCD_D31, + GPIO161_LCD_D32, + GPIO162_LCD_D33, + GPIO163_LCD_D34, + GPIO164_LCD_D35, + GPIO165_LCD_D36, + GPIO166_LCD_D37, + GPIO167_LCD_D38, + GPIO168_LCD_D39, +#endif +); + +static UX500_PINS(mop500_pins_mcde_tvout, +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO78_LCD_D8, + GPIO79_LCD_D9, + GPIO80_LCD_D10, + GPIO81_LCD_D11, + GPIO150_LCDA_CLK, +#endif +); + +static UX500_PINS(mop500_pins_ske, +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO153_KP_I7 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO154_KP_I6 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO155_KP_I5 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO156_KP_I4 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO161_KP_I3 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO162_KP_I2 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO163_KP_I1 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO164_KP_I0 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO157_KP_O7 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO158_KP_O6 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO159_KP_O5 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO160_KP_O4 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO165_KP_O3 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO166_KP_O2 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO167_KP_O1 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO168_KP_O0 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, +#endif +); + +/* sdi0 (removable MMC/SD/SDIO cards) */ +static UX500_PINS(mop500_pins_sdi0, + GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH, + GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH, + GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH, + + GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL, + GPIO23_MC0_CLK | PIN_OUTPUT_LOW, + GPIO24_MC0_CMD | PIN_INPUT_PULLUP, + GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP, + GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP, + GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP, + GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP, +); + +/* sdi1 (WLAN CW1200) */ +static UX500_PINS(mop500_pins_sdi1, + GPIO208_MC1_CLK | PIN_OUTPUT_LOW, + GPIO209_MC1_FBCLK | PIN_INPUT_NOPULL, + GPIO210_MC1_CMD | PIN_INPUT_PULLUP, + GPIO211_MC1_DAT0 | PIN_INPUT_PULLUP, + GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP, + GPIO213_MC1_DAT2 | PIN_INPUT_PULLUP, + GPIO214_MC1_DAT3 | PIN_INPUT_PULLUP, +); + +/* sdi2 (POP eMMC) */ +static UX500_PINS(mop500_pins_sdi2, + GPIO128_MC2_CLK | PIN_OUTPUT_LOW, + GPIO129_MC2_CMD | PIN_INPUT_PULLUP, + GPIO130_MC2_FBCLK | PIN_INPUT_NOPULL, + GPIO131_MC2_DAT0 | PIN_INPUT_PULLUP, + GPIO132_MC2_DAT1 | PIN_INPUT_PULLUP, + GPIO133_MC2_DAT2 | PIN_INPUT_PULLUP, + GPIO134_MC2_DAT3 | PIN_INPUT_PULLUP, + GPIO135_MC2_DAT4 | PIN_INPUT_PULLUP, + GPIO136_MC2_DAT5 | PIN_INPUT_PULLUP, + GPIO137_MC2_DAT6 | PIN_INPUT_PULLUP, + GPIO138_MC2_DAT7 | PIN_INPUT_PULLUP, +); + +/* sdi4 (PCB eMMC) */ +static UX500_PINS(mop500_pins_sdi4, +#ifndef CONFIG_MACH_U8500_SNOWBALL + GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP, + GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP, + GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP, + GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP, + GPIO201_MC4_CMD | PIN_INPUT_PULLUP, + GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL, + GPIO203_MC4_CLK | PIN_OUTPUT_LOW, + GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP, + GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP, + GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP, + GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP, +#endif +); + +static struct ux500_pin_lookup mop500_pins[] = { + PIN_LOOKUP("mcde-dpi", &mop500_pins_mcde_dpi), + PIN_LOOKUP("mcde-tvout", &mop500_pins_mcde_tvout), + PIN_LOOKUP("uart0", &mop500_pins_uart0), + PIN_LOOKUP("nmk-i2c.0", &mop500_pins_i2c0), + PIN_LOOKUP("nmk-i2c.1", &mop500_pins_i2c1), + PIN_LOOKUP("nmk-i2c.2", &mop500_pins_i2c2), + PIN_LOOKUP("nmk-i2c.3", &mop500_pins_i2c3), + PIN_LOOKUP("ske", &mop500_pins_ske), + PIN_LOOKUP("sdi0", &mop500_pins_sdi0), + PIN_LOOKUP("sdi1", &mop500_pins_sdi1), + PIN_LOOKUP("sdi2", &mop500_pins_sdi2), + PIN_LOOKUP("sdi4", &mop500_pins_sdi4), +}; + +/* + * This function is called to force gpio power save + * settings during suspend. + * This is a temporary solution until all drivers are + * controlling their pin settings when in inactive mode. + */ +static void mop500_pins_suspend_force(void) +{ + u32 bankaddr; + u32 w_imsc; + u32 imsc; + u32 mask; + + /* + * Apply HSI GPIO Config for DeepSleep + * + * Bank0 + */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK0_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + mask = 0; + if (machine_is_hrefv60()) + /* Mask away pin 4 (0x10) which is WLAN_IRQ */ + mask |= 0x10; + + writel(0x409C702A & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DIR); + writel(0x001C0022 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DATS); + writel(0x807000 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DATC); + writel(0x5FFFFFFF & ~w_imsc & ~imsc & ~mask, bankaddr + NMK_GPIO_PDIS); + writel(readl(bankaddr + NMK_GPIO_SLPC) & mask, + bankaddr + NMK_GPIO_SLPC); + + /* Bank1 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK1_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + writel(0x3 & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0x1C , bankaddr + NMK_GPIO_DIRC); + writel(0x2 & ~w_imsc, bankaddr + NMK_GPIO_DATC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); + + /* Bank2 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK2_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + mask = 0; + if (machine_is_hrefv60()) + /* Mask away pin 85 (0x200000) which is WLAN_ENABLE */ + mask |= 0x200000; + + writel(0x3D7C0 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DIRS); + writel(0x803C2830 & ~mask, bankaddr + NMK_GPIO_DIRC); + writel(0x3D7C0 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DATC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc & ~mask, bankaddr + NMK_GPIO_PDIS); + /* + * No need to set SLPC (SLPM) register. This can break modem STM + * settings on pins (70-76) because modem is special and needs to + * have its mux connected even in suspend because modem could still + * be on and might send interesting STM debugging data. + */ + + /* Bank3 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK3_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + writel(0x3 & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0x3 & ~w_imsc, bankaddr + NMK_GPIO_DATC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); + + /* Bank4 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK4_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + writel(0x5E000 & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0xFFDA1800 , bankaddr + NMK_GPIO_DIRC); + writel(0x4E000 & ~w_imsc, bankaddr + NMK_GPIO_DATC); + writel(0x10000 & ~w_imsc, bankaddr + NMK_GPIO_DATS); + writel(0xFFFFFFF9 & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); + + /* Bank5 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK5_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + + if (machine_is_hrefv60()) { + /* Make sure that camera pin 170 "XENON_CHARGE" is low */ + writel(0x400 & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0x400 & ~w_imsc, bankaddr + NMK_GPIO_DATC); + } + + writel(0x3FF , bankaddr + NMK_GPIO_DIRC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); + + /* Bank6 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK6_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + mask = 0; + if (!machine_is_hrefv60()) { + /* Mask away pin 215 (0x800000) which is WLAN_ENABLE */ + mask |= 0x800000; + + /* Mask away pin 216 (0x1000000) which is WLAN_IRQ */ + mask |= 0x1000000; + } + /* Mask away pin 212 (0x100000) which is SDIO DAT1 */ + mask |= 0x100000; + + writel(0x8810810 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DIRS); + writel(0xF57EF7EF & ~mask, bankaddr + NMK_GPIO_DIRC); + writel(0x8810810 & ~w_imsc & ~mask, bankaddr + NMK_GPIO_DATC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc & ~mask, bankaddr + NMK_GPIO_PDIS); + writel(readl(bankaddr + NMK_GPIO_SLPC) & mask, + bankaddr + NMK_GPIO_SLPC); + + + /* Bank7 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK7_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + writel(0x1C & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0x63 , bankaddr + NMK_GPIO_DIRC); + writel(0x18 & ~w_imsc, bankaddr + NMK_GPIO_DATC); + writel(0xFFFFFFFF & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); + + /* Bank8 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK8_BASE); + + w_imsc = readl(bankaddr + NMK_GPIO_RWIMSC) | + readl(bankaddr + NMK_GPIO_FWIMSC); + + imsc = readl(bankaddr + NMK_GPIO_RIMSC) | + readl(bankaddr + NMK_GPIO_FIMSC); + + writel(0x2 & ~w_imsc, bankaddr + NMK_GPIO_DIRS); + writel(0xFF0 , bankaddr + NMK_GPIO_DIRC); + writel(0x2 & ~w_imsc, bankaddr + NMK_GPIO_DATS); + writel(0x2 & ~w_imsc & ~imsc, bankaddr + NMK_GPIO_PDIS); + writel(0 , bankaddr + NMK_GPIO_SLPC); +} + +/* + * This function is called to force gpio power save + * mux settings during suspend. + * This is a temporary solution until all drivers are + * controlling their pin settings when in inactive mode. + */ +static void mop500_pins_suspend_force_mux(void) +{ + u32 bankaddr; + + + /* + * Apply HSI GPIO Config for DeepSleep + * + * Bank0 + */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK0_BASE); + + writel(0xE0000000, bankaddr + NMK_GPIO_AFSLA); + writel(0xE0000000, bankaddr + NMK_GPIO_AFSLB); + + /* Bank1 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK1_BASE); + + writel(0x1 , bankaddr + NMK_GPIO_AFSLA); + writel(0x1 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank2 (Nothing needs to be done) */ + + /* Bank3 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK3_BASE); + + writel(0 , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank4 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK4_BASE); + + writel(0x7FF , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank5 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK5_BASE); + + writel(0 , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank6 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK6_BASE); + + writel(0 , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank7 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK7_BASE); + + writel(0 , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + /* Bank8 */ + bankaddr = IO_ADDRESS(U8500_GPIOBANK8_BASE); + + writel(0 , bankaddr + NMK_GPIO_AFSLA); + writel(0 , bankaddr + NMK_GPIO_AFSLB); + + +} + +/* + * passing "pinsfor=" in kernel cmdline allows for custom + * configuration of GPIOs on u8500 derived boards. + */ +static int __init early_pinsfor(char *p) +{ + pinsfor = PINS_FOR_DEFAULT; + + if (strcmp(p, "u9500-21") == 0) + pinsfor = PINS_FOR_U9500_21; + + return 0; +} +early_param("pinsfor", early_pinsfor); + +void __init mop500_pins_init(void) +{ + nmk_config_pins(mop500_pins_common, + ARRAY_SIZE(mop500_pins_common)); + + + if (machine_is_hrefv60()) + nmk_config_pins(mop500_pins_hrefv60, + ARRAY_SIZE(mop500_pins_hrefv60)); + else + nmk_config_pins(mop500_pins_default, + ARRAY_SIZE(mop500_pins_default)); + + ux500_pins_add(mop500_pins, ARRAY_SIZE(mop500_pins)); + + switch (pinsfor) { + case PINS_FOR_U9500_21: + nmk_config_pins(u9500_21_pins, ARRAY_SIZE(u9500_21_pins)); + break; + + case PINS_FOR_DEFAULT: + default: + break; + } + + suspend_set_pins_force_fn(mop500_pins_suspend_force, + mop500_pins_suspend_force_mux); +} diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c new file mode 100644 index 00000000000..ce0c0b5accf --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -0,0 +1,1218 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * 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 + * + * MOP500 board specific initialization for regulators + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/regulator/machine.h> + +#include "board-mop500-regulators.h" +#include "board-mop500-mcde.h" + +/* + * AB8500 Regulator Configuration + */ + +/* ab8500 regulator register initialization */ +struct ab8500_regulator_reg_init + ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { + /* + * VanaRequestCtrl = HP/LP depending on VxRequest + * VpllRequestCtrl = HP/LP depending on VxRequest + * VextSupply1RequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0x00), + /* + * VextSupply2RequestCtrl = HP/LP depending on VxRequest + * VextSupply3RequestCtrl = HP/LP depending on VxRequest + * Vaux1RequestCtrl = HP/LP depending on VxRequest + * Vaux2RequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0x00), + /* + * Vaux3RequestCtrl = HP/LP depending on VxRequest + * SwHPReq = Control through SWValid disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x00), + /* + * Vsmps1SysClkReq1HPValid = enabled + * Vsmps2SysClkReq1HPValid = enabled + * Vsmps3SysClkReq1HPValid = enabled + * VanaSysClkReq1HPValid = disabled + * VpllSysClkReq1HPValid = enabled + * Vaux1SysClkReq1HPValid = disabled + * Vaux2SysClkReq1HPValid = disabled + * Vaux3SysClkReq1HPValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x17), + /* + * VextSupply1SysClkReq1HPValid = disabled + * VextSupply2SysClkReq1HPValid = disabled + * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x40), + /* + * VanaHwHPReq1Valid = disabled + * Vaux1HwHPreq1Valid = disabled + * Vaux2HwHPReq1Valid = disabled + * Vaux3HwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0x00), + /* + * VextSupply1HwHPReq1Valid = disabled + * VextSupply2HwHPReq1Valid = disabled + * VextSupply3HwHPReq1Valid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x00), + /* + * VanaHwHPReq2Valid = disabled + * Vaux1HwHPReq2Valid = disabled + * Vaux2HwHPReq2Valid = disabled + * Vaux3HwHPReq2Valid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0x00), + /* + * VextSupply1HwHPReq2Valid = disabled + * VextSupply2HwHPReq2Valid = disabled + * VextSupply3HwHPReq2Valid = HWReq2 controlled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x04), + /* + * VanaSwHPReqValid = disabled + * Vaux1SwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0x00), + /* + * Vaux2SwHPReqValid = disabled + * Vaux3SwHPReqValid = disabled + * VextSupply1SwHPReqValid = disabled + * VextSupply2SwHPReqValid = disabled + * VextSupply3SwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x00), + /* + * SysClkReq2Valid1 = SysClkReq2 controlled + * SysClkReq3Valid1 = disabled + * SysClkReq4Valid1 = SysClkReq4 controlled + * SysClkReq5Valid1 = disabled + * SysClkReq6Valid1 = SysClkReq6 controlled + * SysClkReq7Valid1 = disabled + * SysClkReq8Valid1 = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0x2a), + /* + * SysClkReq2Valid2 = disabled + * SysClkReq3Valid2 = disabled + * SysClkReq4Valid2 = disabled + * SysClkReq5Valid2 = disabled + * SysClkReq6Valid2 = SysClkReq6 controlled + * SysClkReq7Valid2 = disabled + * SysClkReq8Valid2 = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0x20), + /* + * VTVoutEna = disabled + * Vintcore12Ena = disabled + * Vintcore12Sel = 1.25 V + * Vintcore12LP = inactive (HP) + * VTVoutLP = inactive (HP) + */ + INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0x10), + /* + * VaudioEna = disabled + * VdmicEna = disabled + * Vamic1Ena = disabled + * Vamic2Ena = disabled + */ + INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x00), + /* + * Vamic1_dzout = high-Z when Vamic1 is disabled + * Vamic2_dzout = high-Z when Vamic2 is disabled + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x00), + /* + * VBBN = force OFF + * VBBP = force OFF + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_ARMREGU2, 0x00), + /* + * VBBNSel1 = VBBP = VBBPFB + * VBBPSel1 = 0 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VBBSEL1, 0x00), + /* + * VBBNSel2 = VBBP = VBBPFB + * VBBPSel2 = 0 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VBBSEL2, 0x00), + /* + * Vsmps1Regu = HW control + * Vsmps1SelCtrl = Vsmps1 voltage defined by Vsmsp1Sel2 + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS1REGU, 0x06), + /* + * Vsmps2Regu = force HP + * Vsmps2SelCtrl = Vsmps2 voltage defined by Vsmsp2Sel2 + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS2REGU, 0x05), + /* + * Vsmps3Sel2 = 1.2125 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS3SEL2, 0x29), + /* + * Vsmps3Regu = HW control + * Vsmps3SelCtrl = Vsmps3 voltage defined by Vsmps3Sel2 + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS3REGU, 0x06), + /* + * Vsmps3Sel1 = 1.0 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS3SEL1, 0x18), + /* + * VPll = Hw controlled + * VanaRegu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x02), + /* + * VrefDDREna = disabled + * VrefDDRSleepMode = inactive (no pulldown) + */ + INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x00), + /* + * VextSupply1Regu = HW control + * VextSupply2Regu = HW control + * VextSupply3Regu = Low Power mode + * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0 + * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0 + */ + INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0x1a), + /* + * Vaux1Regu = force HP + * Vaux2Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x01), + /* + * Vrf1Regu = HW control + * Vaux3Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x08), + /* + * Vsmps1 = 1.15V + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x24), + /* + * Vaux1Sel = 2.5 V + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x08), + /* + * Vaux2Sel = 2.9 V + */ + INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0d), + /* + * Vaux3Sel = 2.91 V + */ + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07), + /* + * VextSupply12LP = disabled (no LP) + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x00), + /* + * Vaux1Disch = short discharge time + * Vaux2Disch = short discharge time + * Vaux3Disch = short discharge time + * Vintcore12Disch = short discharge time + * VTVoutDisch = short discharge time + * VaudioDisch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0x00), + /* + * VanaDisch = short discharge time + * VdmicPullDownEna = pulldown disabled when Vdmic is disabled + * VdmicDisch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x00), +}; + +/* vana regulator configuration, for analogue part of displays */ +static struct regulator_consumer_supply ab8500_vana_consumers[] = { + { + .dev_name = "mcde", + .supply = "v-ana", + }, + { + .dev_name = "mmio_camera", + .supply = "v-ana", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.9", + .supply = "ana", + }, +#endif +}; + +#if defined(CONFIG_MACH_U8500_MOP) && (CONFIG_SENSORS1P_MOP) +extern struct platform_device sensors1p_device; +#endif + +/* vaux1 regulator configuration */ +static struct regulator_consumer_supply ab8500_vaux1_consumers[] = { + { + .dev = NULL, + .supply = "v-display", + }, +#if defined(CONFIG_MACH_U8500_MOP) && (CONFIG_SENSORS1P_MOP) + { + .dev = &sensors1p_device.dev, + .supply = "v-proximity", + }, + { + .dev = &sensors1p_device.dev, + .supply = "v-hal", + }, +#endif +#ifdef CONFIG_SENSORS_BH1780 + { + .dev_name = "bh1780", + .supply = "v-als", + }, +#endif +#ifdef CONFIG_SENSORS_LSM303DLH + { + .dev_name = "lsm303dlh.0", + .supply = "v-accel", + }, + { + .dev_name = "lsm303dlh.1", + .supply = "v-mag", + }, +#endif +#ifdef CONFIG_SENSORS_L3G4200D + { + .dev_name = "l3g4200d", + .supply = "v-gyro", + }, +#endif + { + .dev_name = "mmio_camera", + .supply = "v-mmio-camera", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.0", + .supply = "aux1", + }, +#endif + { + .dev_name = "3-005c", + .supply = "avdd", + }, + + { + .dev_name = "3-005d", + .supply = "avdd", + }, + { + .dev_name = "3-004b", + .supply = "vdd", + }, +}; + +/* vaux2 regulator configuration */ +static struct regulator_consumer_supply ab8500_vaux2_consumers[] = { + { + .dev_name = "sdi4", + .supply = "v-eMMC", + }, + { + .dev_name = "ab8500-codec.0", + .supply = "vcc-avswitch", + }, + { + .dev_name = "ab8500-acc-det.0", + .supply = "vcc-avswitch" + }, +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY + { + .dev = &tvout_ab8500_display.dev, + .supply = "v-ab8500-AV-switch", + }, +#endif +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY + { + .dev = &av8100_hdmi.dev, + .supply = "v-av8100-AV-switch", + }, +#endif +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.1", + .supply = "aux2", + }, +#endif +}; + +/* vaux3 regulator configuration */ +static struct regulator_consumer_supply ab8500_vaux3_consumers[] = { + { + .dev_name = "sdi0", + .supply = "v-MMC-SD" + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.2", + .supply = "aux3", + }, +#endif +}; + +/* vtvout regulator configuration, supply for tvout, gpadc, TVOUT LDO */ +static struct regulator_consumer_supply ab8500_vtvout_consumers[] = { +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY + { + .dev = &tvout_ab8500_display.dev, + .supply = "v-tvout", + }, +#endif + { + .supply = "ab8500-gpadc", + }, + { + .dev_name = "ab8500-charger.0", + .supply = "vddadc" + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.4", + .supply = "tvout", + }, +#endif +}; + +/* vaudio regulator configuration, supply for ab8500-vaudio, VAUDIO LDO */ +static struct regulator_consumer_supply ab8500_vaudio_consumers[] = { + { + .supply = "v-audio", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.5", + .supply = "audio", + }, +#endif +}; + +/* vamic1 regulator configuration */ +static struct regulator_consumer_supply ab8500_vamic1_consumers[] = { + { + .supply = "v-amic1", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.6", + .supply = "anamic1", + }, +#endif +}; + +/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ +static struct regulator_consumer_supply ab8500_vamic2_consumers[] = { + { + .supply = "v-amic2", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.7", + .supply = "anamic2", + }, +#endif +}; + +/* supply for v-dmic, VDMIC LDO */ +static struct regulator_consumer_supply ab8500_vdmic_consumers[] = { + { + .supply = "v-dmic", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.8", + .supply = "dmic", + }, +#endif +}; + +/* supply for v-intcore12, VINTCORE12 LDO */ +static struct regulator_consumer_supply ab8500_vintcore_consumers[] = { + { + .supply = "v-intcore", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.3", + .supply = "intcore", + }, +#endif + { + .dev_name = "ab8500-usb.0", + .supply = "v-intcore", + }, + +}; + +/* supply for CG2900 */ +static struct regulator_consumer_supply ab8500_sysclkreq_2_consumers[] = { + { + .dev_name = "cg2900-uart.0", + .supply = "gbf_1v8", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.10", + .supply = "sysclkreq-2", + }, +#endif +}; + +/* supply for CW1200 */ +static struct regulator_consumer_supply ab8500_sysclkreq_4_consumers[] = { + { + .dev_name = "cw1200", + .supply = "wlan_1v8", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.11", + .supply = "sysclkreq-4", + }, +#endif +}; + +/* + * AB8500 regulators + */ +struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { + /* supplies to the display/camera */ + [AB8500_LDO_AUX1] = { + .constraints = { + .name = "ab8500-vaux1", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, /* must be on for display */ + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), + .consumer_supplies = ab8500_vaux1_consumers, + }, + /* supplies to the on-board eMMC */ + [AB8500_LDO_AUX2] = { + .constraints = { + .name = "ab8500-vaux2", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers), + .consumer_supplies = ab8500_vaux2_consumers, + }, + /* supply for VAUX3, supplies to SDcard slots */ + [AB8500_LDO_AUX3] = { + .constraints = { + .name = "ab8500-vaux3", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers), + .consumer_supplies = ab8500_vaux3_consumers, + }, + /* supply for tvout, gpadc, TVOUT LDO */ + [AB8500_LDO_TVOUT] = { + .constraints = { + .name = "ab8500-vtvout", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers), + .consumer_supplies = ab8500_vtvout_consumers, + }, + /* supply for ab8500-vaudio, VAUDIO LDO */ + [AB8500_LDO_AUDIO] = { + .constraints = { + .name = "ab8500-vaudio", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaudio_consumers), + .consumer_supplies = ab8500_vaudio_consumers, + }, + /* supply for v-anamic1 VAMic1-LDO */ + [AB8500_LDO_ANAMIC1] = { + .constraints = { + .name = "ab8500-vamic1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers), + .consumer_supplies = ab8500_vamic1_consumers, + }, + /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ + [AB8500_LDO_ANAMIC2] = { + .constraints = { + .name = "ab8500-vamic2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers), + .consumer_supplies = ab8500_vamic2_consumers, + }, + /* supply for v-dmic, VDMIC LDO */ + [AB8500_LDO_DMIC] = { + .constraints = { + .name = "ab8500-vdmic", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers), + .consumer_supplies = ab8500_vdmic_consumers, + }, + /* supply for v-intcore12, VINTCORE12 LDO */ + [AB8500_LDO_INTCORE] = { + .constraints = { + .name = "ab8500-vintcore", + .min_uV = 1200000, + .max_uV = 1350000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers), + .consumer_supplies = ab8500_vintcore_consumers, + }, + /* supply for U8500 CSI/DSI, VANA LDO */ + [AB8500_LDO_ANA] = { + .constraints = { + .name = "ab8500-vana", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers), + .consumer_supplies = ab8500_vana_consumers, + }, + /* sysclkreq 2 pin */ + [AB8500_SYSCLKREQ_2] = { + .constraints = { + .name = "ab8500-sysclkreq-2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = + ARRAY_SIZE(ab8500_sysclkreq_2_consumers), + .consumer_supplies = ab8500_sysclkreq_2_consumers, + }, + /* sysclkreq 4 pin */ + [AB8500_SYSCLKREQ_4] = { + .constraints = { + .name = "ab8500-sysclkreq-4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = + ARRAY_SIZE(ab8500_sysclkreq_4_consumers), + .consumer_supplies = ab8500_sysclkreq_4_consumers, + }, +}; + +/* + * Power State Regulator Configuration + */ +#define U8500_VAPE_REGULATOR_MIN_VOLTAGE 1800000 +#define U8500_VAPE_REGULATOR_MAX_VOLTAGE 2000000 + +/* vape regulator configuration */ +static struct regulator_consumer_supply u8500_vape_consumers[] = { + { + .supply = "v-ape", + }, + { + .dev_name = "nmk-i2c.0", + .supply = "v-i2c", + }, + { + .dev_name = "nmk-i2c.1", + .supply = "v-i2c", + }, + { + .dev_name = "nmk-i2c.2", + .supply = "v-i2c", + }, + { + .dev_name = "nmk-i2c.3", + .supply = "v-i2c", + }, + { + .dev_name = "sdi0", + .supply = "v-mmc", + }, + { + .dev_name = "sdi1", + .supply = "v-mmc", + }, + { + .dev_name = "sdi2", + .supply = "v-mmc", + }, + { + .dev_name = "sdi4", + .supply = "v-mmc", + }, + { + .dev_name = "dma40.0", + .supply = "v-dma", + }, + { + .dev_name = "ab8500-usb.0", + .supply = "v-ape", + }, + { + .dev_name = "uart0", + .supply = "v-uart", + }, + { + .dev_name = "uart1", + .supply = "v-uart", + }, + { + .dev_name = "uart2", + .supply = "v-uart", + }, + { + .dev_name = "nmk-ske-keypad", + .supply = "v-ape", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.12", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vape_regulator = { + .constraints = { + .name = "u8500-vape", + .min_uV = U8500_VAPE_REGULATOR_MIN_VOLTAGE, + .max_uV = U8500_VAPE_REGULATOR_MAX_VOLTAGE, + .input_uV = 1, /* notional, for set_mode* */ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .consumer_supplies = u8500_vape_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vape_consumers), +}; + +/* varm regulator_configuration */ +static struct regulator_consumer_supply u8500_varm_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.13", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_varm_regulator = { + .constraints = { + .name = "u8500-varm", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_varm_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_varm_consumers), +}; + +/* vmodem regulator configuration */ +static struct regulator_consumer_supply u8500_vmodem_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.14", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vmodem_regulator = { + .constraints = { + .name = "u8500-vmodem", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vmodem_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vmodem_consumers), +}; + +/* vpll regulator configuration */ +static struct regulator_consumer_supply u8500_vpll_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.15", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vpll_regulator = { + .constraints = { + .name = "u8500-vpll", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vpll_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vpll_consumers), +}; + +/* vsmps1 regulator configuration */ +static struct regulator_consumer_supply u8500_vsmps1_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.16", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vsmps1_regulator = { + .constraints = { + .name = "u8500-vsmps1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vsmps1_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps1_consumers), +}; + +/* vsmsp2 regulator configuration */ +static struct regulator_consumer_supply u8500_vsmps2_consumers[] = { + { + .dev_name = "ab8500-usb.0", + .supply = "musb_1v8", + }, + { + .dev_name = "0-0070", + .supply = "hdmi_1v8", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.17", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vsmps2_regulator = { + .constraints = { + .name = "u8500-vsmps2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vsmps2_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps2_consumers), +}; + +/* vsmps3 regulator configuration */ +static struct regulator_consumer_supply u8500_vsmps3_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.18", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vsmps3_regulator = { + .constraints = { + .name = "u8500-vsmps3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vsmps3_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps3_consumers), +}; + +/* vrf1 regulator configuration */ +static struct regulator_consumer_supply u8500_vrf1_consumers[] = { +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.19", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_vrf1_regulator = { + .constraints = { + .name = "u8500-vrf1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_vrf1_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_vrf1_consumers), +}; + +/* + * Power Domain Switch Configuration + */ + +/* SVA MMDSP regulator switch */ +static struct regulator_consumer_supply u8500_svammdsp_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sva-mmdsp", + }, + { + .dev_name = "cm_control", + .supply = "sva-mmdsp", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.20", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_svammdsp_regulator = { + /* dependency to u8500-vape is handled outside regulator framework */ + .constraints = { + .name = "u8500-sva-mmdsp", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_svammdsp_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_svammdsp_consumers), +}; + +/* SVA MMDSP retention regulator switch */ +static struct regulator_consumer_supply u8500_svammdspret_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sva-mmdsp-ret", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.21", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_svammdspret_regulator = { + .constraints = { + .name = "u8500-sva-mmdsp-ret", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_svammdspret_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_svammdspret_consumers), +}; + +/* SVA pipe regulator switch */ +static struct regulator_consumer_supply u8500_svapipe_consumers[] = { + /* Add SVA pipe device supply here */ + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sva-pipe", + }, + { + .dev_name = "cm_control", + .supply = "sva-pipe", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.22", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_svapipe_regulator = { + /* dependency to u8500-vape is handled outside regulator framework */ + .constraints = { + .name = "u8500-sva-pipe", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_svapipe_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_svapipe_consumers), +}; + +/* SIA MMDSP regulator switch */ +static struct regulator_consumer_supply u8500_siammdsp_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sia-mmdsp", + }, + { + .dev_name = "cm_control", + .supply = "sia-mmdsp", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.23", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_siammdsp_regulator = { + /* dependency to u8500-vape is handled outside regulator framework */ + .constraints = { + .name = "u8500-sia-mmdsp", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_siammdsp_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_siammdsp_consumers), +}; + +/* SIA MMDSP retention regulator switch */ +static struct regulator_consumer_supply u8500_siammdspret_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sia-mmdsp-ret", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.24", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_siammdspret_regulator = { + .constraints = { + .name = "u8500-sia-mmdsp-ret", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_siammdspret_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_siammdspret_consumers), +}; + +/* SIA pipe regulator switch */ +static struct regulator_consumer_supply u8500_siapipe_consumers[] = { + /* Add SIA pipe device supply here */ + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sia-pipe", + }, + { + .dev_name = "cm_control", + .supply = "sia-pipe", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.25", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_siapipe_regulator = { + /* dependency to u8500-vape is handled outside regulator framework */ + .constraints = { + .name = "u8500-sia-pipe", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_siapipe_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_siapipe_consumers), +}; + +/* SGA regulator switch */ +static struct regulator_consumer_supply u8500_sga_consumers[] = { + /* Add SGA device supply here */ + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-sga", + }, + { + /* + * The Mali driver doesn't have access to the device when + * requesting the SGA regulator. Therefore only supply name. + */ + .supply = "v-mali", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.26", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_sga_regulator = { + .supply_regulator = "u8500-vape", + .constraints = { + .name = "u8500-sga", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_sga_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_sga_consumers), +}; + +/* B2R2-MCDE regulator switch */ +static struct regulator_consumer_supply u8500_b2r2_mcde_consumers[] = { + { + .dev_name = "b2r2_bus", + .supply = "vsupply", + }, + { + .dev_name = "mcde", + .supply = "vsupply", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-b2r2", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-mcde", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.27", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_b2r2_mcde_regulator = { + .supply_regulator = "u8500-vape", + .constraints = { + .name = "u8500-b2r2-mcde", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_b2r2_mcde_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_b2r2_mcde_consumers), +}; + +/* ESRAM1 and 2 regulator switch */ +static struct regulator_consumer_supply u8500_esram12_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram1", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram2", + }, + { + .dev_name = "cm_control", + .supply = "esram12", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.28", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_esram12_regulator = { + .supply_regulator = "u8500-vape", + .constraints = { + .name = "u8500-esram12", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_esram12_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_esram12_consumers), +}; + +/* ESRAM1 and 2 retention regulator switch */ +static struct regulator_consumer_supply u8500_esram12ret_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram1-ret", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram2-ret", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.29", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_esram12ret_regulator = { + .constraints = { + .name = "u8500-esram12-ret", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_esram12ret_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_esram12ret_consumers), +}; + +/* ESRAM3 and 4 regulator switch */ +static struct regulator_consumer_supply u8500_esram34_consumers[] = { + { + .dev_name = "mcde", + .supply = "v-esram34", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram3", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram4", + }, + { + .dev_name = "cm_control", + .supply = "esram34", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.30", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_esram34_regulator = { + .supply_regulator = "u8500-vape", + .constraints = { + .name = "u8500-esram34", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_esram34_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_esram34_consumers), +}; + +/* ESRAM3 and 4 retention regulator switch */ +static struct regulator_consumer_supply u8500_esram34ret_consumers[] = { + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram3-ret", + }, + { + /* NOTE! This is a temporary supply for prcmu_set_hwacc */ + .supply = "hwacc-esram4-ret", + }, +#ifdef CONFIG_U8500_REGULATOR_DEBUG + { + .dev_name = "reg-virt-consumer.31", + .supply = "test", + }, +#endif +}; + +struct regulator_init_data u8500_esram34ret_regulator = { + .constraints = { + .name = "u8500-esram34-ret", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u8500_esram34ret_consumers, + .num_consumer_supplies = ARRAY_SIZE(u8500_esram34ret_consumers), +}; diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h new file mode 100644 index 00000000000..5a4f9560b1e --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-regulators.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * MOP500 board specific initialization for regulators + */ + +#ifndef __BOARD_MOP500_REGULATORS_H +#define __BOARD_MOP500_REGULATORS_H + +#include <linux/regulator/machine.h> +#include <linux/regulator/ab8500.h> + +/* AB8500 regulators */ +extern struct ab8500_regulator_reg_init + ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS]; +extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; + +/* U8500 specific regulators */ +extern struct regulator_init_data u8500_vape_regulator; +extern struct regulator_init_data u8500_varm_regulator; +extern struct regulator_init_data u8500_vmodem_regulator; +extern struct regulator_init_data u8500_vpll_regulator; +extern struct regulator_init_data u8500_vsmps1_regulator; +extern struct regulator_init_data u8500_vsmps2_regulator; +extern struct regulator_init_data u8500_vsmps3_regulator; +extern struct regulator_init_data u8500_vrf1_regulator; + +/* U8500 specific regulator switches */ +extern struct regulator_init_data u8500_svammdsp_regulator; +extern struct regulator_init_data u8500_svammdspret_regulator; +extern struct regulator_init_data u8500_svapipe_regulator; +extern struct regulator_init_data u8500_siammdsp_regulator; +extern struct regulator_init_data u8500_siammdspret_regulator; +extern struct regulator_init_data u8500_siapipe_regulator; +extern struct regulator_init_data u8500_sga_regulator; +extern struct regulator_init_data u8500_b2r2_mcde_regulator; +extern struct regulator_init_data u8500_esram12_regulator; +extern struct regulator_init_data u8500_esram12ret_regulator; +extern struct regulator_init_data u8500_esram34_regulator; +extern struct regulator_init_data u8500_esram34ret_regulator; + +#endif diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c new file mode 100644 index 00000000000..b1acb64ae54 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-sdi.c @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2010 ST-Ericsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/amba/mmci.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/core.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <plat/ste_dma40.h> +#include <plat/pincfg.h> +#include <mach/devices.h> +#include <mach/gpio.h> +#include <mach/ste-dma40-db8500.h> + +#include "devices-db8500.h" +#include "pins-db8500.h" +#include "board-mop500.h" + + +/* + * SDI0 (SD/MMC card) + */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg sdi0_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV29_SD_MM0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi0_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV29_SD_MM0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static void sdi0_configure(void) +{ + int ret; + int gpio[2]; + if (machine_is_snowball()) { + gpio[0] = SNOWBALL_SDMMC_EN_GPIO; + gpio[1] = SNOWBALL_SDMMC_1V8_3V_GPIO; + } else if (machine_is_hrefv60()) { + gpio[0] = HREFV60_SDMMC_EN_GPIO; + gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; + } else { + gpio[0] = EGPIO_PIN_17; + gpio[1] = EGPIO_PIN_18; + } + ret = gpio_request(gpio[0], "level shifter enable"); + if (!ret) + ret = gpio_request(gpio[1], "level shifter select"); + + if (ret) { + printk(KERN_WARNING "unable to config gpios for level shifter.\n"); + return; + } + + /* Select the default 2.9V and eanble level shifter */ + gpio_direction_output(gpio[1], 0); + gpio_direction_output(gpio[0], 1); +} + +static void sdi0_vdd_handler(struct device *dev, unsigned int vdd, + unsigned char power_mode) +{ + int gpio[2]; + + if (machine_is_snowball()) { + gpio[0] = SNOWBALL_SDMMC_EN_GPIO; + gpio[1] = SNOWBALL_SDMMC_1V8_3V_GPIO; + } else if (machine_is_hrefv60()) { + gpio[0] = HREFV60_SDMMC_EN_GPIO; + gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; + } else { + gpio[0] = EGPIO_PIN_17; + gpio[1] = EGPIO_PIN_18; + } + switch (power_mode) { + case MMC_POWER_UP: + case MMC_POWER_ON: + /* + * Level shifter voltage should depend on vdd to when deciding + * on either 1.8V or 2.9V. Once the decision has been made the + * level shifter must be disabled and re-enabled with a changed + * select signal in order to switch the voltage. Since there is + * no framework support yet for indicating 1.8V in vdd, use the + * default 2.9V. + */ + gpio_direction_output(gpio[1], 0); + /* Enable level shifter */ + gpio_direction_output(gpio[0], 1); + udelay(100); + break; + case MMC_POWER_OFF: + gpio_direction_output(gpio[1], 0); + /* Disable level shifter */ + gpio_direction_output(gpio[0], 0); + break; + } +} + +static struct mmci_platform_data mop500_sdi0_data = { + .vcc = "v-mmc", + .vcard = "v-MMC-SD", + .vdd_handler = sdi0_vdd_handler, + .disable = 50, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_DISABLE, + .gpio_wp = -1, + .sigdir = MMCI_ST_DIRFBCLK | + MMCI_ST_DIRCMD | + MMCI_ST_DIRDAT0 | + MMCI_ST_DIRDAT2, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi0_dma_cfg_rx, + .dma_tx_param = &sdi0_dma_cfg_tx, +#endif +}; + +/* + * SDI1 (SDIO WLAN) + */ +static irqreturn_t sdio_irq(int irq, void *dev_id) +{ + struct mmc_host *host = dev_id; + + /* + * Signal an sdio irq for the sdio client. + * If we are in suspend state the host has been claimed + * by the pm framework, which prevents any sdio request + * to be served until the host gets resumed and released. + */ + mmc_signal_sdio_irq(host); + + return IRQ_HANDLED; +} + +static void sdio_config_irq(struct mmc_host *host, + bool cfg_as_dat1, + int irq_pin, + pin_cfg_t irq_dat1, + pin_cfg_t irq_gpio) +{ + /* + * If the pin mux switch or interrupt registration fails we're in deep + * trouble and there is no decent recovery. + */ + if (!gpio_is_valid(irq_pin)) { + dev_err(mmc_dev(host), + "invalid irq pin (%d) for sdio irq\n", irq_pin); + return; + } + + if (!cfg_as_dat1) { + + /* + * SDIO irq shall be handled as a gpio irq. We configure the + * dat[1] as gpio and register a gpio irq handler. + */ + + if (nmk_config_pin(irq_gpio, 0)) + dev_err(mmc_dev(host), + "err config irq gpio (%lu) for sdio irq\n", + irq_gpio); + + /* We use threaded irq */ + if (request_threaded_irq(gpio_to_irq(irq_pin), + NULL, + sdio_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + dev_driver_string(mmc_dev(host)), + host)) + dev_err(mmc_dev(host), + "err request_threaded_irq for sdio irq\n"); + + /* + * Set the irq as a wakeup irq to be able to be woken up + * from the suspend state and thus trigger a resume of + * the system. + */ + if (enable_irq_wake(gpio_to_irq(irq_pin))) + dev_err(mmc_dev(host), + "err enabling wakeup irq for sdio irq\n"); + + /* + * Workaround to fix PL180 hw-problem of missing sdio irqs. + * If the DAT1 line has been asserted low we signal an sdio + * irq. + */ + if (gpio_request(irq_pin, dev_driver_string(mmc_dev(host)))) + dev_err(mmc_dev(host), + "err requesting irq for sdio irq\n"); + + if (!gpio_get_value(irq_pin)) + mmc_signal_sdio_irq(host); + + gpio_free(irq_pin); + + } else { + + /* + * SDIO irq shall be handled as dat[1] irq by the mmci + * driver. Configure the gpio back into dat[1] and remove + * the gpio irq handler. + */ + if (disable_irq_wake(gpio_to_irq(irq_pin))) + dev_err(mmc_dev(host), + "err disabling wakeup irq for sdio irq\n"); + + free_irq(gpio_to_irq(irq_pin), host); + + if (nmk_config_pin(irq_dat1, 0)) + dev_err(mmc_dev(host), + "err config irq dat1 (%lu) for sdio irq\n", + irq_dat1); + + } +} + +static void wakeup_handler_sdi1(struct mmc_host *host, bool wakeup) +{ + if (host->card && mmc_card_sdio(host->card) && host->sdio_irqs) + sdio_config_irq(host, + wakeup, + 212, + GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP, + GPIO212_GPIO | PIN_INPUT_PULLUP); +} + +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg sdi1_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV32_SD_MM1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi1_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV32_SD_MM1_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data mop500_sdi1_data = { + .vcc = "v-mmc", + .disable = 50, + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_DISABLE | + MMC_CAP_SDIO_IRQ | + MMC_CAP_BROKEN_SDIO_CMD53, + .pm_flags = MMC_PM_KEEP_POWER, + .gpio_cd = -1, + .gpio_wp = -1, + .wakeup_handler = wakeup_handler_sdi1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi1_dma_cfg_rx, + .dma_tx_param = &sdi1_dma_cfg_tx, +#endif +}; + +/* + * SDI2 (POPed eMMC) + */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg sdi2_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV28_SD_MM2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +static struct stedma40_chan_cfg sdi2_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV28_SD_MM2_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data mop500_sdi2_data = { + .vcc = "v-mmc", + .disable = 50, + .ocr_mask = MMC_VDD_165_195, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_DISABLE, + .pm_flags = MMC_PM_KEEP_POWER, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi2_dma_cfg_rx, + .dma_tx_param = &sdi2_dma_cfg_tx, +#endif +}; + +/* + * SDI4 (On-board eMMC) + */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg sdi4_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV42_SD_MM4_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi4_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV42_SD_MM4_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data mop500_sdi4_data = { + .vcc = "v-mmc", + .vcard = "v-eMMC", + .disable = 50, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_DISABLE, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi4_dma_cfg_rx, + .dma_tx_param = &sdi4_dma_cfg_tx, +#endif +}; + +static int __init mop500_sdi_init(void) +{ + /* POP eMMC on v1.0 has problems with high speed */ + if (!cpu_is_u8500v10()) + mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED; + + /* sdi2 on snowball is in ATL_B mode for FSMC (LAN) */ + if (!machine_is_snowball()) + db8500_add_sdi2(&mop500_sdi2_data); + + db8500_add_sdi4(&mop500_sdi4_data); + + sdi0_configure(); + if (machine_is_snowball()) { + mop500_sdi0_data.gpio_cd = SNOWBALL_SDMMC_CD_GPIO; + mop500_sdi0_data.cd_invert = true; + mop500_sdi0_data.sigdir = 0; + } else if (machine_is_hrefv60()) + mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO; + else + mop500_sdi0_data.gpio_cd = EGPIO_PIN_3; + + db8500_add_sdi0(&mop500_sdi0_data); + db8500_add_sdi1(&mop500_sdi1_data); + + return 0; +} + +fs_initcall(mop500_sdi_init); diff --git a/arch/arm/mach-ux500/board-mop500-stuib.c b/arch/arm/mach-ux500/board-mop500-stuib.c new file mode 100644 index 00000000000..595677a87c1 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-stuib.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/lsm303dlh.h> +#include <linux/l3g4200d.h> +#include <plat/pincfg.h> +#include "pins-db8500.h" + +#include <linux/input/lps001wp.h> + +#include "board-mop500.h" + +static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata_st_uib = { + .name_a = "lsm303dlh.0", + .name_m = "lsm303dlh.1", + .axis_map_x = 0, + .axis_map_y = 1, + .axis_map_z = 2, + .negative_x = 1, + .negative_y = 1, + .negative_z = 0, +}; + +static struct l3g4200d_gyr_platform_data __initdata l3g4200d_pdata_u8500 = { + .name_gyr = "l3g4200d", + .axis_map_x = 1, + .axis_map_y = 0, + .axis_map_z = 2, + .negative_x = 0, + .negative_y = 0, + .negative_z = 1, +}; + +static struct lps001wp_prs_platform_data __initdata lps001wp_pdata = { + .poll_interval = 500, + .min_interval = 10, +}; + +static struct i2c_board_info __initdata mop500_i2c2_devices_st_uib[] = { + { + /* LSM303DLH Accelerometer */ + I2C_BOARD_INFO("lsm303dlh_a", 0x18), + .platform_data = &lsm303dlh_pdata_st_uib, + }, + { + /* LSM303DLH Magnetometer */ + I2C_BOARD_INFO("lsm303dlh_m", 0x1E), + .platform_data = &lsm303dlh_pdata_st_uib, + }, + { + /* L3G4200D Gyroscope */ + I2C_BOARD_INFO("l3g4200d", 0x68), + .platform_data = &l3g4200d_pdata_u8500, + }, + { + /* LSP001WM Barometer */ + I2C_BOARD_INFO("lps001wp_prs_sysfs", 0x5C), + .platform_data = &lps001wp_pdata, + }, +}; + +void __init mop500_stuib_init(void) +{ + if (machine_is_hrefv60()) { + lsm303dlh_pdata_st_uib.irq_a1 = HREFV60_ACCEL_INT1_GPIO; + lsm303dlh_pdata_st_uib.irq_a2 = HREFV60_ACCEL_INT2_GPIO; + lsm303dlh_pdata_st_uib.irq_m = HREFV60_MAGNET_DRDY_GPIO; + } else { + lsm303dlh_pdata_st_uib.irq_a1 = EGPIO_PIN_10; + lsm303dlh_pdata_st_uib.irq_a2 = EGPIO_PIN_11; + lsm303dlh_pdata_st_uib.irq_m = EGPIO_PIN_1; + } + mop500_uib_i2c_add(2, mop500_i2c2_devices_st_uib, + ARRAY_SIZE(mop500_i2c2_devices_st_uib)); +} diff --git a/arch/arm/mach-ux500/board-mop500-u8500uib.c b/arch/arm/mach-ux500/board-mop500-u8500uib.c new file mode 100644 index 00000000000..01e047db40a --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-u8500uib.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/lsm303dlh.h> +#include <linux/l3g4200d.h> +#include <plat/pincfg.h> +#include "pins-db8500.h" + +#include "board-mop500.h" + +/* For U8500 UIB */ +static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata_u8500_uib = { + .name_a = "lsm303dlh.0", + .name_m = "lsm303dlh.1", + .axis_map_x = 1, + .axis_map_y = 0, + .axis_map_z = 2, + .negative_x = 1, + .negative_y = 1, + .negative_z = 1, +}; + +static struct l3g4200d_gyr_platform_data __initdata l3g4200d_pdata_u8500_uib = { + .name_gyr = "l3g4200d", + .axis_map_x = 1, + .axis_map_y = 0, + .axis_map_z = 2, + .negative_x = 0, + .negative_y = 0, + .negative_z = 1, +}; +static struct i2c_board_info __initdata mop500_i2c2_devices_u8500_uib[] = { + { + /* LSM303DLH Accelerometer */ + I2C_BOARD_INFO("lsm303dlh_a", 0x18), + .platform_data = &lsm303dlh_pdata_u8500_uib, + }, + { + /* LSM303DLH Magnetometer */ + I2C_BOARD_INFO("lsm303dlh_m", 0x1E), + .platform_data = &lsm303dlh_pdata_u8500_uib, + }, + { + /* L3G4200D Gyroscope */ + I2C_BOARD_INFO("l3g4200d", 0x68), + .platform_data = &l3g4200d_pdata_u8500_uib, + }, +}; + +void __init mop500_u8500uib_init(void) +{ + if (machine_is_hrefv60()) { + lsm303dlh_pdata_u8500_uib.irq_a1 = HREFV60_ACCEL_INT1_GPIO; + lsm303dlh_pdata_u8500_uib.irq_a2 = HREFV60_ACCEL_INT2_GPIO; + lsm303dlh_pdata_u8500_uib.irq_m = HREFV60_MAGNET_DRDY_GPIO; + } else { + lsm303dlh_pdata_u8500_uib.irq_a1 = EGPIO_PIN_10; + lsm303dlh_pdata_u8500_uib.irq_a2 = EGPIO_PIN_11; + lsm303dlh_pdata_u8500_uib.irq_m = EGPIO_PIN_1; + } + mop500_uib_i2c_add(2, mop500_i2c2_devices_u8500_uib, + ARRAY_SIZE(mop500_i2c2_devices_u8500_uib)); +} diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c new file mode 100644 index 00000000000..c95ca380bd8 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-uib.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2 + */ + +#define pr_fmt(fmt) "mop500-uib: " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> + +#include <mach/hardware.h> +#include "board-mop500.h" + +enum mop500_uib { + STUIB, + U8500UIB, +}; + +struct uib { + const char *name; + const char *option; + void (*init)(void); +}; + +static struct uib __initdata mop500_uibs[] = { + [STUIB] = { + .name = "ST-UIB", + .option = "stuib", + .init = mop500_stuib_init, + }, + [U8500UIB] = { + .name = "U8500-UIB", + .option = "u8500uib", + .init = mop500_u8500uib_init, + }, +}; + +static struct uib __initdata *mop500_uib; + +static int __init mop500_uib_setup(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mop500_uibs); i++) { + struct uib *uib = &mop500_uibs[i]; + + if (!strcmp(str, uib->option)) { + mop500_uib = uib; + break; + } + } + + if (i == ARRAY_SIZE(mop500_uibs)) + pr_err("invalid uib= option (%s)\n", str); + + return 1; +} +__setup("uib=", mop500_uib_setup); + +/* + * The UIBs are detected after the I2C host controllers are registered, so + * i2c_register_board_info() can't be used. + */ +void mop500_uib_i2c_add(int busnum, struct i2c_board_info const *info, + unsigned n) +{ + struct i2c_adapter *adap; + struct i2c_client *client; + int i; + + adap = i2c_get_adapter(busnum); + if (!adap) { + pr_err("failed to get adapter i2c%d\n", busnum); + return; + } + + for (i = 0; i < n; i++) { + client = i2c_new_device(adap, &info[i]); + if (!client) + pr_err("failed to register %s to i2c%d\n", + info[i].type, busnum); + } + + i2c_put_adapter(adap); +} + +static void __init __mop500_uib_init(struct uib *uib, const char *why) +{ + pr_info("%s (%s)\n", uib->name, why); + uib->init(); +} + +/* + * Detect the UIB attached based on the presence or absence of i2c devices. + */ +static int __init mop500_uib_init(void) +{ + struct uib *uib = mop500_uib; + + if (ux500_is_svp() || !cpu_is_u8500()) + return -ENODEV; + + if (uib) { + __mop500_uib_init(uib, "from uib= boot argument"); + return 0; + } + + { +#ifndef CONFIG_MACH_U8500_SNOWBALL + struct i2c_adapter *i2c0; + int ret; + + i2c0 = i2c_get_adapter(0); + if (!i2c0) { + __mop500_uib_init(&mop500_uibs[STUIB], + "fallback, could not get i2c0"); + return -ENODEV; + } + + /* U8500-UIB has the TC35893 at 0x44 on I2C0, the ST-UIB doesn't. */ + ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + i2c_put_adapter(i2c0); + + if (ret == 0) + uib = &mop500_uibs[U8500UIB]; + else +#endif + uib = &mop500_uibs[STUIB]; + } + + __mop500_uib_init(uib, "detected"); + + return 0; +} + +module_init(mop500_uib_init); diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index bb8d7b77181..95fb0871240 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -8,70 +8,740 @@ * published by the Free Software Foundation. * */ +#include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/io.h> #include <linux/amba/bus.h> #include <linux/amba/pl022.h> +#include <linux/interrupt.h> #include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/hsi/hsi.h> +#include <linux/i2s/i2s.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/stmpe.h> +#include <linux/mfd/tc35892.h> +#include <linux/i2c/lp5521.h> +#include <linux/power_supply.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/ab8500.h> +#include <linux/input/bu21013.h> +#include <linux/ste_timed_vibra.h> +#include <linux/mmio.h> +#include <linux/cw1200-wlan.h> +#include <linux/spi/stm_msp.h> +#include <linux/leds_pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/mfd/ab8500/denc.h> +#include <linux/mfd/ab8500/ab8500-gpio.h> +#include <linux/mfd/cg2900.h> + +#ifdef CONFIG_USB_ANDROID +#include <linux/usb/android_composite.h> +#endif + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci.h> -#include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <plat/pincfg.h> +#include <plat/ske.h> #include <plat/i2c.h> +#include <plat/ste_dma40.h> -#include <mach/hardware.h> +#include <mach/devices.h> +#include <mach/sensors1p.h> +#include <mach/ab8500-accdet.h> +#include <mach/ste_audio_io.h> #include <mach/setup.h> +#include <mach/tc35893-keypad.h> +#include <video/av8100.h> #include <mach/devices.h> +#include <mach/irqs.h> +#include <mach/ste-dma40-db8500.h> +#ifdef CONFIG_DB8500_MLOADER +#include <mach/mloader-dbx500.h> +#endif + +#include <sound/ux500_ab8500_ext.h> + +#include "devices-cg2900.h" +#include "devices-db8500.h" +#include "board-mop500-regulators.h" +#include "regulator-u8500.h" +#include "pins-db8500.h" +#include "board-mop500-bm.h" +#include "board-mop500.h" +#include "pins.h" + +#define IRQ_KP 1 /*To DO*/ + +#ifdef CONFIG_USB_ANDROID +#define PUBLIC_ID_BACKUPRAM1 (U8500_BACKUPRAM1_BASE + 0x0FC0) +#define USB_SERIAL_NUMBER_LEN 31 +#endif + +/* + * This variable holds the number of touchscreen (bu21013) enabled. + */ +static int cs_en_check; + +/* + * ux500 keymaps + * + * Organized row-wise as on the UIB, starting at the top-left + * + * we support two key layouts, specific to requirements. The first + * keylayout includes controls for power/volume a few generic keys; + * the second key layout contains the full numeric layout, enter/back/left + * buttons along with a "."(dot), specifically for connectivity testing + */ +static const unsigned int ux500_keymap[] = { +#ifdef CONFIG_KEYLAYOUT_LAYOUT1 + KEY(2, 5, KEY_END), + KEY(4, 1, KEY_HOME), + KEY(3, 5, KEY_VOLUMEDOWN), + KEY(1, 3, KEY_EMAIL), + KEY(5, 2, KEY_RIGHT), + KEY(5, 0, KEY_BACKSPACE), + + KEY(0, 5, KEY_MENU), + KEY(7, 6, KEY_ENTER), + KEY(4, 5, KEY_0), + KEY(6, 7, KEY_DOT), + KEY(3, 4, KEY_UP), + KEY(3, 3, KEY_DOWN), + + KEY(6, 4, KEY_SEND), + KEY(6, 2, KEY_BACK), + KEY(4, 2, KEY_VOLUMEUP), + KEY(5, 5, KEY_SPACE), + KEY(4, 3, KEY_LEFT), + KEY(3, 2, KEY_SEARCH), +#else +#ifdef CONFIG_KEYLAYOUT_LAYOUT2 + KEY(2, 5, KEY_RIGHT), + KEY(4, 1, KEY_ENTER), + KEY(3, 5, KEY_MENU), + KEY(1, 3, KEY_3), + KEY(5, 2, KEY_6), + KEY(5, 0, KEY_9), + + KEY(0, 5, KEY_UP), + KEY(7, 6, KEY_DOWN), + KEY(4, 5, KEY_0), + KEY(6, 7, KEY_2), + KEY(3, 4, KEY_5), + KEY(3, 3, KEY_8), + + KEY(6, 4, KEY_LEFT), + KEY(6, 2, KEY_BACK), + KEY(4, 2, KEY_KPDOT), + KEY(5, 5, KEY_1), + KEY(4, 3, KEY_4), + KEY(3, 2, KEY_7), +#else +#warning "No keypad layout defined." +#endif +#endif +}; + +static struct matrix_keymap_data ux500_keymap_data = { + .keymap = ux500_keymap, + .keymap_size = ARRAY_SIZE(ux500_keymap), +}; + +/* + * STMPE1601 + */ +static struct stmpe_keypad_platform_data stmpe1601_keypad_data = { + .debounce_ms = 64, + .scan_count = 8, + .no_autorepeat = true, + .keymap_data = &ux500_keymap_data, +}; + +static struct stmpe_platform_data stmpe1601_data = { + .id = 1, + .blocks = STMPE_BLOCK_KEYPAD, + .irq_trigger = IRQF_TRIGGER_FALLING, + .irq_base = MOP500_STMPE1601_IRQ(0), + .keypad = &stmpe1601_keypad_data, + .autosleep = true, + .autosleep_timeout = 1024, +}; + +/* + * Nomadik SKE keypad + */ +#define ROW_PIN_I0 164 +#define ROW_PIN_I1 163 +#define ROW_PIN_I2 162 +#define ROW_PIN_I3 161 +#define ROW_PIN_I4 156 +#define ROW_PIN_I5 155 +#define ROW_PIN_I6 154 +#define ROW_PIN_I7 153 +#define COL_PIN_O0 168 +#define COL_PIN_O1 167 +#define COL_PIN_O2 166 +#define COL_PIN_O3 165 +#define COL_PIN_O4 160 +#define COL_PIN_O5 159 +#define COL_PIN_O6 158 +#define COL_PIN_O7 157 + +static int ske_kp_rows[] = { + ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3, + ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7, +}; +static int ske_kp_cols[] = { + COL_PIN_O0, COL_PIN_O1, COL_PIN_O2, COL_PIN_O3, + COL_PIN_O4, COL_PIN_O5, COL_PIN_O6, COL_PIN_O7, +}; + +static bool ske_config; +/* + * ske_set_gpio_row: request and set gpio rows + */ +static int ske_set_gpio_row(int gpio) +{ + int ret; + + if (!ske_config) { + ret = gpio_request(gpio, "ske-kp"); + if (ret < 0) { + pr_err("ske_set_gpio_row: gpio request failed\n"); + return ret; + } + } + + ret = gpio_direction_output(gpio, 1); + if (ret < 0) { + pr_err("ske_set_gpio_row: gpio direction failed\n"); + gpio_free(gpio); + } + + return ret; +} + +/* + * ske_kp_init - enable the gpio configuration + */ +static int ske_kp_init(void) +{ + struct ux500_pins *pins; + int ret, i; + + pins = ux500_pins_get("ske"); + if (pins) + ux500_pins_enable(pins); + + for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { + ret = ske_set_gpio_row(ske_kp_rows[i]); + if (ret < 0) { + pr_err("ske_kp_init: failed init\n"); + return ret; + } + } + if (!ske_config) + ske_config = true; + + return 0; +} + +static int ske_kp_exit(void) +{ + struct ux500_pins *pins; + + pins = ux500_pins_get("ske"); + if (pins) + ux500_pins_disable(pins); + + return 0; +} + +static struct ske_keypad_platform_data mop500_ske_keypad_data = { + .init = ske_kp_init, + .exit = ske_kp_exit, + .gpio_input_pins = ske_kp_rows, + .gpio_output_pins = ske_kp_cols, + .keymap_data = &ux500_keymap_data, + .no_autorepeat = true, + .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */ + .kcol = SKE_KPD_MAX_COLS, + .debounce_ms = 20, /* in timeout period */ + .switch_delay = 200, /* in jiffies */ +}; + +static struct av8100_platform_data av8100_plat_data = { + .irq = GPIO_TO_IRQ(192), + .reset = 196, +#ifdef CONFIG_MACH_U8500_SNOWBALL + .inputclk_id = "sysclk", +#else + .inputclk_id = "sysclk2", +#endif + .regulator_pwr_id = "hdmi_1v8", + .alt_powerupseq = true, + .mclk_freq = 3, /* MCLK_RNG_31_38 */ +}; + +/* + * TC35892 Expander + */ + +#if defined(CONFIG_MFD_TC35892) +static struct tc35892_gpio_platform_data tc35892_gpio_platform_data = { + .gpio_base = U8500_NR_GPIO, +}; + +static struct tc35892_platform_data tc35892_data = { + .gpio = &tc35892_gpio_platform_data, + .irq_base = MOP500_EGPIO_IRQ_BASE, +}; +#endif + +static const unsigned int nuib_keymap[] = { + KEY(3, 1, KEY_END), + KEY(4, 1, KEY_HOME), + KEY(6, 4, KEY_VOLUMEDOWN), + KEY(4, 2, KEY_EMAIL), + KEY(3, 3, KEY_RIGHT), + KEY(2, 5, KEY_BACKSPACE), + + KEY(6, 7, KEY_MENU), + KEY(5, 0, KEY_ENTER), + KEY(4, 3, KEY_0), + KEY(3, 4, KEY_DOT), + KEY(5, 2, KEY_UP), + KEY(3, 5, KEY_DOWN), + + KEY(4, 5, KEY_SEND), + KEY(0, 5, KEY_BACK), + KEY(6, 2, KEY_VOLUMEUP), + KEY(1, 3, KEY_SPACE), + KEY(7, 6, KEY_LEFT), + KEY(5, 5, KEY_SEARCH), +}; + +static struct matrix_keymap_data nuib_keymap_data = { + .keymap = nuib_keymap, + .keymap_size = ARRAY_SIZE(nuib_keymap), +}; + +#if defined(CONFIG_KEYBOARD_TC35893) +static struct tc35893_platform_data tc35893_data = { + .krow = TC_KPD_ROWS, + .kcol = TC_KPD_COLUMNS, + .debounce_period = TC_KPD_DEBOUNCE_PERIOD, + .settle_time = TC_KPD_SETTLE_TIME, + .irqtype = (IRQF_TRIGGER_FALLING), + .irq = GPIO_TO_IRQ(218), + .enable_wakeup = true, + .keymap_data = &nuib_keymap_data, + .no_autorepeat = true, +}; +#endif + +static struct lp5521_platform_data lp5521_data = { + .mode = LP5521_MODE_DIRECT_CONTROL, + .label = "uib-led", + .red_present = true, + .green_present = true, + .blue_present = true, +}; + +/** + * Touch panel related platform specific initialization + */ + +/** + * bu21013_gpio_board_init : configures the touch panel. + * @reset_pin: reset pin number + * This function can be used to configures + * the voltage and reset the touch panel controller. + */ +static int bu21013_gpio_board_init(int reset_pin) +{ + int retval = 0; + + cs_en_check++; + if (cs_en_check == 1) { + retval = gpio_request(reset_pin, "touchp_reset"); + if (retval) { + printk(KERN_ERR "Unable to request gpio reset_pin"); + return retval; + } + retval = gpio_direction_output(reset_pin, 1); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", + __func__); + return retval; + } + gpio_set_value(reset_pin, 1); + } + return retval; +} + +/** + * bu21013_gpio_board_exit : deconfigures the touch panel controller + * @reset_pin: reset pin number + * This function can be used to deconfigures the chip selection + * for touch panel controller. + */ +static int bu21013_gpio_board_exit(int reset_pin) +{ + int retval = 0; + + if (cs_en_check == 1) { + retval = gpio_direction_output(reset_pin, 0); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", + __func__); + return retval; + } + gpio_set_value(reset_pin, 0); + + gpio_free(reset_pin); + } + cs_en_check--; + return retval; +} -static void ab4500_spi_cs_control(u32 command) +/** + * bu21013_read_pin_val : get the interrupt pin value + * This function can be used to get the interrupt pin value for touch panel + * controller. + */ +static int bu21013_read_pin_val(void) { - /* set the FRM signal, which is CS - TODO */ + return gpio_get_value(TOUCH_GPIO_PIN); } -struct pl022_config_chip ab4500_chip_info = { - .lbm = LOOPBACK_DISABLED, - .com_mode = INTERRUPT_TRANSFER, - .iface = SSP_INTERFACE_MOTOROLA_SPI, - /* we can act as master only */ - .hierarchy = SSP_MASTER, - .slave_tx_disable = 0, - .endian_rx = SSP_RX_MSB, - .endian_tx = SSP_TX_MSB, - .data_size = SSP_DATA_BITS_24, - .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, - .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, - .clk_phase = SSP_CLK_SECOND_EDGE, - .clk_pol = SSP_CLK_POL_IDLE_HIGH, - .cs_control = ab4500_spi_cs_control, +static struct bu21013_platform_device tsc_plat_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .irq_read_val = bu21013_read_pin_val, + .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .x_max_res = 480, + .y_max_res = 864, + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, + .portrait = true, + .has_ext_clk = true, + .enable_ext_clk = false, +#if CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE == 270 + .x_flip = true, + .y_flip = false, +#else + .x_flip = false, + .y_flip = true, +#endif +}; + +static struct bu21013_platform_device tsc_cntl2_plat_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .irq_read_val = bu21013_read_pin_val, + .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .x_max_res = 480, + .y_max_res = 864, + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, + .portrait = true, + .has_ext_clk = true, + .enable_ext_clk = false, +#if CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE == 270 + .x_flip = true, + .y_flip = false, +#else + .x_flip = false, + .y_flip = true, +#endif +}; + +static struct ab3550_platform_data ab3550_plf_data = { + .irq = { + .base = 0, + .count = 0, + }, + .dev_data = { + }, + .dev_data_sz = { + }, + .init_settings = NULL, + .init_settings_sz = 0, }; -static struct spi_board_info u8500_spi_devices[] = { +static struct i2c_board_info __initdata mop500_i2c0_devices[] = { +#if defined(CONFIG_MFD_TC35892) { - .modalias = "ab8500", - .controller_data = &ab4500_chip_info, - .max_speed_hz = 12000000, - .bus_num = 0, - .chip_select = 0, - .mode = SPI_MODE_0, - .irq = IRQ_AB4500, + + I2C_BOARD_INFO("tc35892", 0x42), + .platform_data = &tc35892_data, + .irq = GPIO_TO_IRQ(217), + }, +#endif + { + /* STMPE1601 on UIB */ + I2C_BOARD_INFO("stmpe1601", 0x40), + .irq = NOMADIK_GPIO_TO_IRQ(218), + .platform_data = &stmpe1601_data, + .flags = I2C_CLIENT_WAKE, /* enable wakeup */ }, +#if defined(CONFIG_KEYBOARD_TC35893) + { + /* TC35893 keypad */ + I2C_BOARD_INFO("tc35893-kp", 0x44), + .platform_data = &tc35893_data, + .flags = I2C_CLIENT_WAKE, /* enable wakeup */ + }, +#endif + { + I2C_BOARD_INFO("av8100", 0x70), + .platform_data = &av8100_plat_data, + }, + { + /* FIXME - address TBD, TODO */ + I2C_BOARD_INFO("uib-kpd", 0x45), + }, + { + /* Audio step-up */ + I2C_BOARD_INFO("tps61052", 0x33), + } +}; +static struct i2c_board_info __initdata mop500_i2c1_devices[] = { + { + /* GPS - Address TBD, FIXME */ + I2C_BOARD_INFO("gps", 0x68), + }, + { + /* AB3550 */ + I2C_BOARD_INFO("ab3550", 0x4A), + .irq = -1, + .platform_data = &ab3550_plf_data, + } +}; +static struct i2c_board_info __initdata mop500_i2c2_devices[] = { + { + /* ST 3D accelerometer @ 0x3A(w),0x3B(r) */ + I2C_BOARD_INFO("lis302dl", 0x1D), + }, + { + /* ASAHI KASEI AK8974 magnetometer, addr TBD FIXME */ + I2C_BOARD_INFO("ak8974", 0x1), + }, +#if defined(CONFIG_SENSORS_BH1780) + { + /* Rohm BH1780GLI ambient light sensor */ + I2C_BOARD_INFO("bh1780", 0x29), + }, +#endif + { + /* RGB LED driver, there are 1st and 2nd, TODO */ + I2C_BOARD_INFO("lp5521", 0x33), + .platform_data = &lp5521_data, + }, +}; +static struct i2c_board_info __initdata mop500_i2c3_devices[] = { + { + /* NFC - Address TBD, FIXME */ + I2C_BOARD_INFO("nfc", 0x68), + }, +#if defined(CONFIG_TOUCHSCREEN_BU21013) + { + /* Touschscreen */ + I2C_BOARD_INFO("bu21013_ts", 0x5C), + .platform_data = &tsc_plat_device, + }, + { + /* Touschscreen */ + I2C_BOARD_INFO("bu21013_ts", 0x5D), + .platform_data = &tsc_cntl2_plat_device, + }, +#endif }; -static struct pl022_ssp_controller ssp0_platform_data = { - .bus_id = 0, - /* pl022 not yet supports dma */ - .enable_dma = 0, - /* on this platform, gpio 31,142,144,214 & - * 224 are connected as chip selects - */ - .num_chipselect = 5, +/* + * MSP-SPI + */ + +#define NUM_MSP_CLIENTS 10 + +static struct stm_msp_controller mop500_msp2_spi_data = { + .id = MSP_2_CONTROLLER, + .num_chipselect = NUM_MSP_CLIENTS, + .base_addr = U8500_MSP2_BASE, + .device_name = "msp2", +}; + +/* + * SSP + */ + +#define NUM_SSP_CLIENTS 10 + +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg ssp0_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV8_SSP0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg ssp0_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV8_SSP0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct pl022_ssp_controller mop500_ssp0_data = { + .bus_id = SSP_0_CONTROLLER, + .num_chipselect = NUM_SSP_CLIENTS, +#ifdef CONFIG_STE_DMA40 + .enable_dma = 1, + .dma_filter = stedma40_filter, + .dma_rx_param = &ssp0_dma_cfg_rx, + .dma_tx_param = &ssp0_dma_cfg_tx, +#endif + +}; + +#ifdef CONFIG_SENSORS1P_MOP +static struct sensors1p_config sensors1p_config = { + /* SFH7741 */ + .proximity = { + .startup_time = 120, /* ms */ + .regulator = "v-proximity", + }, + /* HED54XXU11 */ + .hal = { + .startup_time = 100, /* Actually, I have no clue. */ + .regulator = "v-hal", + }, +}; + +struct platform_device sensors1p_device = { + .name = "sensors1p", + .dev = { + .platform_data = (void *)&sensors1p_config, + }, +}; +#endif +#ifdef CONFIG_USB_ANDROID + +static char *usb_functions_adb[] = { +#ifdef CONFIG_USB_ANDROID_MASS_STORAGE + "usb_mass_storage", +#endif +#ifdef CONFIG_USB_ANDROID_ECM + "cdc_ethernet", +#endif +#ifdef CONFIG_USB_ANDROID_RNDIS + "rndis", +#endif +#ifdef CONFIG_USB_ANDROID_ACM + "acm", +#endif +#ifdef CONFIG_USB_ANDROID_ADB + "adb", +#endif }; -#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ -static struct nmk_i2c_controller u8500_i2c##id##_data = { \ +static struct android_usb_product usb_products[] = { + { + .product_id = 0x2323, + .num_functions = ARRAY_SIZE(usb_functions_adb), + .functions = usb_functions_adb, + }, +}; + +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x04cc, + .product_id = 0x2323, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "ST-Ericsson", + .serial_number = "0123456789ABCDEF0123456789ABCDE", + .num_products = ARRAY_SIZE(usb_products), + .products = usb_products, + .num_functions = ARRAY_SIZE(usb_functions_adb), + .functions = usb_functions_adb, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +#ifdef CONFIG_USB_ANDROID_MASS_STORAGE +static struct usb_mass_storage_platform_data mass_storage_pdata = { + .nluns = 2, + .vendor = "ST-Ericsson", + .product = "Android Phone", + .release = 0x0100, +}; + +static struct platform_device usb_mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &mass_storage_pdata, + }, +}; +#endif /* CONFIG_USB_ANDROID_MASS_STORAGE */ + +#ifdef CONFIG_USB_ANDROID_ECM +static struct usb_ether_platform_data usb_ecm_pdata = { + .ethaddr = {0x02, 0x11, 0x22, 0x33, 0x44, 0x55}, + .vendorID = 0x04cc, + .vendorDescr = "ST Ericsson", +}; + +static struct platform_device usb_ecm_device = { + .name = "cdc_ethernet", + .id = -1, + .dev = { + .platform_data = &usb_ecm_pdata, + }, +}; +#endif /* CONFIG_USB_ANDROID_ECM */ + +#ifdef CONFIG_USB_ANDROID_RNDIS +static struct usb_ether_platform_data usb_rndis_pdata = { + .ethaddr = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55}, + .vendorID = 0x04cc, + .vendorDescr = "ST Ericsson", +}; + +static struct platform_device usb_rndis_device = { + .name = "rndis", + .id = -1, + .dev = { + .platform_data = &usb_rndis_pdata, + }, +}; +#endif /* CONFIG_USB_ANDROID_RNDIS */ + +#endif /* CONFIG_USB_ANDROID */ + +#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm) \ +static struct nmk_i2c_controller mop500_i2c##id##_data = { \ /* \ * slave data setup time, which is \ * 250 ns,100ns,10ns which is 14,6,2 \ @@ -85,6 +755,8 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \ .rft = _rft, \ /* std. mode operation */ \ .clk_freq = clk, \ + /* Slave response timeout(ms) */\ + .timeout = t_out, \ .sm = _sm, \ } @@ -94,57 +766,822 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \ * Tx & Rx FIFO threshold values as 1 and standard * mode of operation */ -U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); -U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); -U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); -U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); +#ifndef CONFIG_MACH_U8500_SNOWBALL +U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 400000, 200, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 400000, 200, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(2, 0xe, 1, 8, 400000, 200, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(3, 0xe, 1, 8, 400000, 200, I2C_FREQ_MODE_FAST); +#else +U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +#endif + +#ifdef CONFIG_HSI +static struct hsi_board_info __initdata u8500_hsi_devices[] = { + { + .name = "hsi_char", + .hsi_id = 0, + .port = 0, + .tx_cfg = { + .mode = HSI_MODE_STREAM, + .channels = 2, + .speed = 100000, + {.arb_mode = HSI_ARB_RR}, + }, + .rx_cfg = { + .mode = HSI_MODE_STREAM, + .channels = 2, + .speed = 200000, + {.flow = HSI_FLOW_SYNC}, + }, + }, + { + .name = "hsi_test", + .hsi_id = 0, + .port = 0, + .tx_cfg = { + .mode = HSI_MODE_FRAME, + .channels = 2, + .speed = 100000, + {.arb_mode = HSI_ARB_RR}, + }, + .rx_cfg = { + .mode = HSI_MODE_FRAME, + .channels = 2, + .speed = 200000, + {.flow = HSI_FLOW_SYNC}, + }, + }, + { + .name = "cfhsi_v3_driver", + .hsi_id = 0, + .port = 0, + .tx_cfg = { + .mode = HSI_MODE_STREAM, + .channels = 2, + .speed = 20000, + {.arb_mode = HSI_ARB_RR}, + }, + .rx_cfg = { + .mode = HSI_MODE_STREAM, + .channels = 2, + .speed = 200000, + {.flow = HSI_FLOW_SYNC}, + }, + }, +}; +#endif + +#ifdef CONFIG_INPUT_AB8500_ACCDET +static struct ab8500_accdet_platform_data ab8500_accdet_pdata = { + .btn_keycode = KEY_MEDIA, + .accdet1_dbth = ACCDET1_TH_1200mV | ACCDET1_DB_70ms, + .accdet2122_th = ACCDET21_TH_1000mV | ACCDET22_TH_1000mV, + .video_ctrl_gpio = AB8500_PIN_GPIO35, +}; +#endif + +#ifdef CONFIG_AB8500_GPIO +static struct ab8500_gpio_platform_data ab8500_gpio_pdata = { + .gpio_base = AB8500_PIN_GPIO1, +/* #ifndef CONFIG_MACH_U8500_SNOWBALL */ + .irq_base = MOP500_AB8500_VIR_GPIO_IRQ_BASE, +/* #endif */ + /* config_reg is the initial configuration of ab8500 pins. + * The pins can be configured as GPIO or alt functions based + * on value present in GpioSel1 to GpioSel6 and AlternatFunction + * register. This is the array of 7 configuration settings. + * One has to compile time decide these settings. Below is the + * explaination of these setting + * GpioSel1 = 0x07 => Pin GPIO1 (SysClkReq2) + * Pin GPIO2 (SysClkReq3) + * Pin GPIO3 (SysClkReq4) + * Pin GPIO4 (SysClkReq6) are configured as GPIO + * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO + * GpioSel3 = 0x80 => Pin GPIO24 (SysClkReq7) is configured as GPIO + * GpioSel4 = 0x01 => Pin GPIO25 (SysClkReq8) is configured as GPIO + * GpioSel5 = 0x7A => Pin GPIO36 (ApeSpiClk) + Pin GPIO37 (ApeSpiCSn) + Pin GPIO38 (ApeSpiDout) + Pin GPIO39 (ApeSpiDin) are configured as GPIO + * GpioSel6 = 0x02 => Pin GPIO42 (SysClkReq5) is configured as GPIO + * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured + * as GPIO then this register selectes the alternate fucntions + */ + .config_reg = {0x0F, 0x1E, 0x80, 0x01, + 0x7A, 0x02, 0x00}, +}; +#endif + +#ifdef CONFIG_AB8500_DENC +static struct ab8500_denc_platform_data ab8500_denc_pdata = { + .ddr_enable = true, + .ddr_little_endian = false, +}; +#endif + +static struct regulator_init_data *u8500_regulators[U8500_NUM_REGULATORS] = { + [U8500_REGULATOR_VAPE] = &u8500_vape_regulator, + [U8500_REGULATOR_VARM] = &u8500_varm_regulator, +/* #ifndef CONFIG_MACH_U8500_SNOWBALL */ + [U8500_REGULATOR_VMODEM] = &u8500_vmodem_regulator, +/* #endif */ + [U8500_REGULATOR_VPLL] = &u8500_vpll_regulator, + [U8500_REGULATOR_VSMPS1] = &u8500_vsmps1_regulator, + [U8500_REGULATOR_VSMPS2] = &u8500_vsmps2_regulator, + [U8500_REGULATOR_VSMPS3] = &u8500_vsmps3_regulator, + [U8500_REGULATOR_VRF1] = &u8500_vrf1_regulator, + [U8500_REGULATOR_SWITCH_SVAMMDSP] = &u8500_svammdsp_regulator, + [U8500_REGULATOR_SWITCH_SVAMMDSPRET] = &u8500_svammdspret_regulator, + [U8500_REGULATOR_SWITCH_SVAPIPE] = &u8500_svapipe_regulator, + [U8500_REGULATOR_SWITCH_SIAMMDSP] = &u8500_siammdsp_regulator, + [U8500_REGULATOR_SWITCH_SIAMMDSPRET] = &u8500_siammdspret_regulator, + [U8500_REGULATOR_SWITCH_SIAPIPE] = &u8500_siapipe_regulator, + [U8500_REGULATOR_SWITCH_SGA] = &u8500_sga_regulator, + [U8500_REGULATOR_SWITCH_B2R2_MCDE] = &u8500_b2r2_mcde_regulator, + [U8500_REGULATOR_SWITCH_ESRAM12] = &u8500_esram12_regulator, + [U8500_REGULATOR_SWITCH_ESRAM12RET] = &u8500_esram12ret_regulator, + [U8500_REGULATOR_SWITCH_ESRAM34] = &u8500_esram34_regulator, + [U8500_REGULATOR_SWITCH_ESRAM34RET] = &u8500_esram34ret_regulator, +}; + +static struct platform_device u8500_regulator_dev = { + .name = "u8500-regulators", + .id = 0, + .dev = { + .platform_data = u8500_regulators, + }, +}; + +static struct ab8500_audio_platform_data ab8500_audio_plat_data = { + .ste_gpio_altf_init = msp13_i2s_init, + .ste_gpio_altf_exit = msp13_i2s_exit, +}; + +/* + * NOTE! The regulator configuration below must be in exactly the same order as + * the regulator description in the driver, see drivers/regulator/ab8500.c + */ +static struct ab8500_platform_data ab8500_platdata = { + .irq_base = MOP500_AB8500_IRQ_BASE, + .pm_power_off = true, + .regulator_reg_init = ab8500_regulator_reg_init, + .num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init), + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), +#ifdef CONFIG_AB8500_DENC + .denc = &ab8500_denc_pdata, +#endif + .audio = &ab8500_audio_plat_data, + .battery = &ab8500_bm_data, + .charger = &ab8500_charger_plat_data, + .btemp = &ab8500_btemp_plat_data, + .fg = &ab8500_fg_plat_data, + .chargalg = &ab8500_chargalg_plat_data, +#ifdef CONFIG_AB8500_GPIO + .gpio = &ab8500_gpio_pdata, +#endif +#ifdef CONFIG_INPUT_AB8500_ACCDET + .accdet = &ab8500_accdet_pdata, +#endif +}; + +static struct resource ab8500_resources[] = { + [0] = { + .start = IRQ_DB8500_AB8500, + .end = IRQ_DB8500_AB8500, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device ux500_ab8500_device = { + .name = "ab8500-i2c", + .id = 0, + .dev = { + .platform_data = &ab8500_platdata, + }, + .num_resources = 1, + .resource = ab8500_resources, +}; + +#ifdef CONFIG_MFD_CG2900 +#define CG2900_BT_ENABLE_GPIO 170 +#define CG2900_GBF_ENA_RESET_GPIO 171 +#define WLAN_PMU_EN_GPIO 226 +#define SNOWBALL_WLAN_PMU_EN_GPIO 161 +#define CG2900_BT_CTS_GPIO 0 + +enum cg2900_gpio_pull_sleep cg2900_sleep_gpio[21] = { + CG2900_NO_PULL, /* GPIO 0: PTA_CONFX */ + CG2900_PULL_DN, /* GPIO 1: PTA_STATUS */ + CG2900_NO_PULL, /* GPIO 2: UART_CTSN */ + CG2900_PULL_UP, /* GPIO 3: UART_RTSN */ + CG2900_PULL_UP, /* GPIO 4: UART_TXD */ + CG2900_NO_PULL, /* GPIO 5: UART_RXD */ + CG2900_PULL_DN, /* GPIO 6: IOM_DOUT */ + CG2900_NO_PULL, /* GPIO 7: IOM_FSC */ + CG2900_NO_PULL, /* GPIO 8: IOM_CLK */ + CG2900_NO_PULL, /* GPIO 9: IOM_DIN */ + CG2900_PULL_DN, /* GPIO 10: PWR_REQ */ + CG2900_PULL_DN, /* GPIO 11: HOST_WAKEUP */ + CG2900_PULL_DN, /* GPIO 12: IIS_DOUT */ + CG2900_NO_PULL, /* GPIO 13: IIS_WS */ + CG2900_NO_PULL, /* GPIO 14: IIS_CLK */ + CG2900_NO_PULL, /* GPIO 15: IIS_DIN */ + CG2900_PULL_DN, /* GPIO 16: PTA_FREQ */ + CG2900_PULL_DN, /* GPIO 17: PTA_RF_ACTIVE */ + CG2900_NO_PULL, /* GPIO 18: NotConnected (J6428) */ + CG2900_NO_PULL, /* GPIO 19: EXT_DUTY_CYCLE */ + CG2900_NO_PULL, /* GPIO 20: EXT_FRM_SYNCH */ +}; + +static struct platform_device ux500_cg2900_device = { + .name = "cg2900", +}; + +#ifdef CONFIG_MFD_CG2900_CHIP +static struct platform_device ux500_cg2900_chip_device = { + .name = "cg2900-chip", + .dev = { + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_CG2900_CHIP */ + +#ifdef CONFIG_MFD_STLC2690_CHIP +static struct platform_device ux500_stlc2690_chip_device = { + .name = "stlc2690-chip", + .dev = { + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_STLC2690_CHIP */ -static struct amba_device *amba_devs[] __initdata = { - &ux500_uart0_device, - &ux500_uart1_device, - &ux500_uart2_device, - &u8500_ssp0_device, +#ifdef CONFIG_MFD_CG2900_TEST +static struct cg2900_platform_data cg2900_test_platform_data = { + .bus = HCI_VIRTUAL, + .gpio_sleep = cg2900_sleep_gpio, }; -/* add any platform devices here - TODO */ +static struct platform_device ux500_cg2900_test_device = { + .name = "cg2900-test", + .dev = { + .parent = &ux500_cg2900_device.dev, + .platform_data = &cg2900_test_platform_data, + }, +}; +#endif /* CONFIG_MFD_CG2900_TEST */ + +#ifdef CONFIG_MFD_CG2900_UART +static struct resource cg2900_uart_resources_pre_v60[] = { + { + .start = CG2900_GBF_ENA_RESET_GPIO, + .end = CG2900_GBF_ENA_RESET_GPIO, + .flags = IORESOURCE_IO, + .name = "gbf_ena_reset", + }, + { +#ifndef CONFIG_MACH_U8500_SNOWBALL + .start = WLAN_PMU_EN_GPIO, + .end = WLAN_PMU_EN_GPIO, +#else + .start = SNOWBALL_WLAN_PMU_EN_GPIO, + .end = SNOWBALL_WLAN_PMU_EN_GPIO, +#endif + .flags = IORESOURCE_IO, + .name = "pmu_en", + }, + { + .start = CG2900_BT_ENABLE_GPIO, + .end = CG2900_BT_ENABLE_GPIO, + .flags = IORESOURCE_IO, + .name = "bt_enable", + }, + { + .start = CG2900_BT_CTS_GPIO, + .end = CG2900_BT_CTS_GPIO, + .flags = IORESOURCE_IO, + .name = "cts_gpio", + }, + { + .start = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .end = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .flags = IORESOURCE_IRQ, + .name = "cts_irq", + }, +}; + +static struct resource cg2900_uart_resources[] = { + { + .start = CG2900_GBF_ENA_RESET_GPIO, + .end = CG2900_GBF_ENA_RESET_GPIO, + .flags = IORESOURCE_IO, + .name = "gbf_ena_reset", + }, + { + .start = WLAN_PMU_EN_GPIO, + .end = WLAN_PMU_EN_GPIO, + .flags = IORESOURCE_IO, + .name = "pmu_en", + }, + { + .start = CG2900_BT_CTS_GPIO, + .end = CG2900_BT_CTS_GPIO, + .flags = IORESOURCE_IO, + .name = "cts_gpio", + }, + { + .start = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .end = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .flags = IORESOURCE_IRQ, + .name = "cts_irq", + }, +}; + +static pin_cfg_t cg2900_uart_enabled[] = { + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH +}; + +static pin_cfg_t cg2900_uart_disabled[] = { + GPIO0_GPIO | PIN_INPUT_PULLUP, /* CTS pull up. */ + GPIO1_GPIO | PIN_OUTPUT_HIGH, /* RTS high-flow off. */ + GPIO2_GPIO | PIN_INPUT_PULLUP, /* RX pull down. */ + GPIO3_GPIO | PIN_OUTPUT_LOW /* TX low - break on. */ +}; + +static struct cg2900_platform_data cg2900_uart_platform_data = { + .bus = HCI_UART, + .gpio_sleep = cg2900_sleep_gpio, + .uart = { + .n_uart_gpios = 4, + .uart_enabled = cg2900_uart_enabled, + .uart_disabled = cg2900_uart_disabled, + }, +}; + +static struct platform_device ux500_cg2900_uart_device = { + .name = "cg2900-uart", + .dev = { + .platform_data = &cg2900_uart_platform_data, + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_CG2900_UART */ +#endif /* CONFIG_MFD_CG2900 */ + +#ifdef CONFIG_LEDS_PWM +static struct led_pwm pwm_leds_data[] = { + [0] = { + .name = "lcd-backlight", + .pwm_id = 1, + .max_brightness = 255, + .lth_brightness = 90, + .pwm_period_ns = 1023, + }, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY + [1] = { + .name = "sec-lcd-backlight", + .pwm_id = 2, + .max_brightness = 255, + .lth_brightness = 90, + .pwm_period_ns = 1023, + }, +#endif +}; + + + +static struct led_pwm_platform_data u8500_leds_data = { +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY + .num_leds = 2, +#else + .num_leds = 1, +#endif + .leds = pwm_leds_data, +}; + +static struct platform_device ux500_leds_device = { + .name = "leds_pwm", + .dev = { + .platform_data = &u8500_leds_data, + }, +}; +#endif + +#ifdef CONFIG_BACKLIGHT_PWM +static struct platform_pwm_backlight_data u8500_backlight_data[] = { + [0] = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 200, + .lth_brightness = 90, + .pwm_period_ns = 1023, + }, + [1] = { + .pwm_id = 2, + .max_brightness = 255, + .dft_brightness = 200, + .lth_brightness = 90, + .pwm_period_ns = 1023, + }, +}; + +static struct platform_device ux500_backlight_device[] = { + [0] = { + .name = "pwm-backlight", + .id = 0, + .dev = { + .platform_data = &u8500_backlight_data[0], + }, + }, + [1] = { + .name = "pwm-backlight", + .id = 1, + .dev = { + .platform_data = &u8500_backlight_data[1], + }, + }, +}; +#endif + +/* Force feedback vibrator device */ +static struct platform_device ste_ff_vibra_device = { + .name = "ste_ff_vibra" +}; + +/* For details check ste_timed_vibra docbook */ +static struct ste_timed_vibra_platform_data ste_timed_vibra_plat_data = { + .boost_level = 100, + .boost_time = 40, + .on_level = 50, + .off_level = 50, + .off_time = 20, +#ifdef CONFIG_SND_SOC_UX500_AB8500 + .timed_vibra_control = ux500_ab8500_audio_pwm_vibra, +#endif +}; + +/* Timed output vibrator device */ +static struct platform_device ste_timed_output_vibra_device = { + .name = "ste_timed_output_vibra", + .dev = { + .platform_data = &ste_timed_vibra_plat_data, + }, +}; + +static struct wlan1200_platform_data hrefv60_plat_data = { + .gpio_irq = 4, + .gpio_enable = 85, +}; + +static struct wlan1200_platform_data hrefv50_plat_data = { + .gpio_irq = 216, + .gpio_enable = 215, +}; + +#define PRCC_K_SOFTRST_SET 0x18 +#define PRCC_K_SOFTRST_CLEAR 0x1C +static struct ux500_pins *uart0_pins; +static void ux500_pl011_reset(void) +{ + void __iomem *prcc_rst_set, *prcc_rst_clr; + + prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + + PRCC_K_SOFTRST_SET); + prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + + PRCC_K_SOFTRST_CLEAR); + + /* Activate soft reset PRCC_K_SOFTRST_CLEAR */ + writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr); + udelay(1); + + /* Release soft reset PRCC_K_SOFTRST_SET */ + writel((readl(prcc_rst_set) | 0x1), prcc_rst_set); + udelay(1); +} + +static void ux500_pl011_init(void) +{ + int ret; + + if (!uart0_pins) { + uart0_pins = ux500_pins_get("uart0"); + if (!uart0_pins) { + pr_err("pl011: uart0 pins_get failed\n"); + return; + } + } + + ret = ux500_pins_enable(uart0_pins); + if (ret) + pr_err("pl011: uart0 pins_enable failed\n"); +} + +static void ux500_pl011_exit(void) +{ + int ret; + + if (uart0_pins) { + ret = ux500_pins_disable(uart0_pins); + if (ret) + pr_err("pl011: uart0 pins_disable failed\n"); + } +} + +static struct uart_amba_plat_data ux500_pl011_pdata = { + .init = ux500_pl011_init, + .exit = ux500_pl011_exit, + .reset = ux500_pl011_reset, +}; + +static struct platform_device *u8500_platform_devices[] __initdata = { + /*TODO - add platform devices here */ +#ifdef CONFIG_SENSORS1P_MOP + &sensors1p_device, +#endif +#ifdef CONFIG_LEDS_PWM + &ux500_leds_device, +#endif +#ifdef CONFIG_BACKLIGHT_PWM + &ux500_backlight_device[0], + &ux500_backlight_device[1], +#endif +#ifdef CONFIG_STM_TRACE + &ux500_stm_device, +#endif +}; static struct platform_device *platform_devs[] __initdata = { - &u8500_i2c0_device, - &ux500_i2c1_device, - &ux500_i2c2_device, - &ux500_i2c3_device, + &u8500_shrm_device, + &ste_ff_vibra_device, + &ste_timed_output_vibra_device, +#ifdef CONFIG_U8500_MMIO + &ux500_mmio_device, +#endif + &ux500_musb_device, + &ux500_hwmem_device, + &ux500_mcde_device, + &ux500_b2r2_device, + &u8500_thsens_device, +#ifdef CONFIG_STE_TRACE_MODEM + &u8500_trace_modem, +#endif +#ifdef CONFIG_ANDROID_PMEM + &u8500_pmem_hwb_device, +#endif +#ifdef CONFIG_CRYPTO_DEV_UX500_HASH + &ux500_hash1_device, +#endif + &ux500_cryp1_device, +#ifdef CONFIG_USB_ANDROID + &android_usb_device, +#ifdef CONFIG_USB_ANDROID_MASS_STORAGE + &usb_mass_storage_device, +#endif +#ifdef CONFIG_USB_ANDROID_ECM + &usb_ecm_device, +#endif +#ifdef CONFIG_USB_ANDROID_RNDIS + &usb_rndis_device, +#endif +#endif +#ifdef CONFIG_DB8500_MLOADER + &mloader_fw_device, +#endif +#ifdef CONFIG_HSI + &u8500_hsi_device, +#endif }; -static void __init u8500_init_machine(void) +static void __init mop500_i2c_init(void) +{ + db8500_add_i2c0(&mop500_i2c0_data); + db8500_add_i2c1(&mop500_i2c1_data); + db8500_add_i2c2(&mop500_i2c2_data); + db8500_add_i2c3(&mop500_i2c3_data); + + i2c_register_board_info(0, ARRAY_AND_SIZE(mop500_i2c0_devices)); + i2c_register_board_info(1, ARRAY_AND_SIZE(mop500_i2c1_devices)); + i2c_register_board_info(2, ARRAY_AND_SIZE(mop500_i2c2_devices)); + i2c_register_board_info(3, ARRAY_AND_SIZE(mop500_i2c3_devices)); +} + +static void __init mop500_spi_init(void) +{ + db8500_add_ssp0(&mop500_ssp0_data); + db8500_add_msp2_spi(&mop500_msp2_spi_data); +} + +static void __init mop500_uart_init(void) { - int i; + db8500_add_uart0(&ux500_pl011_pdata); + db8500_add_uart1(); + db8500_add_uart2(); +} + +#ifdef CONFIG_USB_ANDROID +/* + * Public Id is a Unique number for each board and is stored + * in Backup RAM at address 0x80151FC0, ..FC4, FC8, FCC and FD0. + * + * This function reads the Public Ids from this address and returns + * a single string, which can be used as serial number for USB. + * Input parameter - serial_number should be of 'len' bytes long +*/ +static void fetch_usb_serial_no(int len) +{ + u32 buf[5]; + void __iomem *backup_ram = NULL; + + if (len > strlen(android_usb_pdata.serial_number)) { + printk(KERN_ERR "$$ serial number is too long! truncating\n"); + len = strlen(android_usb_pdata.serial_number); + } + + backup_ram = ioremap(PUBLIC_ID_BACKUPRAM1, 0x14); + + if (backup_ram) { + buf[0] = readl(backup_ram); + buf[1] = readl(backup_ram + 4); + buf[2] = readl(backup_ram + 8); + buf[3] = readl(backup_ram + 0x0c); + buf[4] = readl(backup_ram + 0x10); + + snprintf(android_usb_pdata.serial_number, len+1, + "%.8X%.8X%.8X%.8X%.8X", + buf[0], buf[1], buf[2], buf[3], buf[4]); + iounmap(backup_ram); + } else { + printk(KERN_ERR "$$ ioremap failed\n"); + } +} +#endif - u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data; - ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data; - ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data; - ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data; +static void device_gpio_cfg(void) +{ + if (machine_is_hrefv60()) { + tsc_plat_device.cs_pin = HREFV60_TOUCH_RST_GPIO; + tsc_cntl2_plat_device.cs_pin = HREFV60_TOUCH_RST_GPIO; +#ifdef CONFIG_SENSORS1P_MOP + sensors1p_config.proximity.pin = HREFV60_PROX_SENSE_GPIO; + sensors1p_config.hal.pin = HREFV60_HAL_SW_GPIO; +#endif + } else { + tsc_plat_device.cs_pin = EGPIO_PIN_13; + tsc_cntl2_plat_device.cs_pin = EGPIO_PIN_13; +#ifdef CONFIG_SENSORS1P_MOP + sensors1p_config.proximity.pin = EGPIO_PIN_7; + sensors1p_config.hal.pin = EGPIO_PIN_8; +#endif + } +} - u8500_ssp0_device.dev.platform_data = &ssp0_platform_data; +static void cw1200_gpio_cfg(void) +{ + if (machine_is_hrefv60()) + wlan1200_set_platdata(&hrefv60_plat_data); + else + wlan1200_set_platdata(&hrefv50_plat_data); +} - /* Register the active AMBA devices on this board */ - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) - amba_device_register(amba_devs[i], &iomem_resource); +/* + * On boards hrefpv60 and later, the accessory insertion/removal, + * button press/release are inverted. +*/ +static void accessory_detect_config(void) +{ +#ifndef CONFIG_MACH_U8500_SNOWBALL + if (machine_is_hrefv60()) + ab8500_accdet_pdata.is_detection_inverted = true; + else + ab8500_accdet_pdata.is_detection_inverted = false; +#endif +} - platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); +static void __init mop500_init_machine(void) +{ + device_gpio_cfg(); + cw1200_gpio_cfg(); + accessory_detect_config(); - spi_register_board_info(u8500_spi_devices, - ARRAY_SIZE(u8500_spi_devices)); +#ifdef CONFIG_REGULATOR + platform_device_register(&u8500_regulator_dev); +#endif u8500_init_devices(); + +#ifdef CONFIG_USB_ANDROID + fetch_usb_serial_no(USB_SERIAL_NUMBER_LEN); +#endif + + platform_add_devices(platform_devs, + ARRAY_SIZE(platform_devs)); + + mop500_pins_init(); + + platform_device_register(&ux500_ab8500_device); + +#ifdef CONFIG_MFD_CG2900 +#ifdef CONFIG_MFD_CG2900_TEST + dcg2900_init_platdata(&cg2900_test_platform_data); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_UART + dcg2900_init_platdata(&cg2900_uart_platform_data); +#endif /* CONFIG_MFD_CG2900_UART */ + + platform_device_register(&ux500_cg2900_device); +#ifdef CONFIG_MFD_CG2900_UART + if (machine_is_hrefv60()) { + ux500_cg2900_uart_device.num_resources = + ARRAY_SIZE(cg2900_uart_resources); + ux500_cg2900_uart_device.resource = + cg2900_uart_resources; + } else { + ux500_cg2900_uart_device.num_resources = + ARRAY_SIZE(cg2900_uart_resources_pre_v60); + ux500_cg2900_uart_device.resource = + cg2900_uart_resources_pre_v60; + } + + platform_device_register(&ux500_cg2900_uart_device); +#endif /* CONFIG_MFD_CG2900_UART */ +#ifdef CONFIG_MFD_CG2900_TEST + platform_device_register(&ux500_cg2900_test_device); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_CHIP + platform_device_register(&ux500_cg2900_chip_device); +#endif /* CONFIG_MFD_CG2900_CHIP */ +#ifdef CONFIG_MFD_STLC2690_CHIP + platform_device_register(&ux500_stlc2690_chip_device); +#endif /* CONFIG_MFD_STLC2690_CHIP */ +#endif /* CONFIG_MFD_CG2900 */ + + mop500_i2c_init(); + mop500_msp_init(); + mop500_spi_init(); + mop500_uart_init(); + +#ifndef CONFIG_MACH_U8500_SNOWBALL + db8500_add_ske_keypad(&mop500_ske_keypad_data); +#endif + +#ifdef CONFIG_HSI + hsi_register_board_info(u8500_hsi_devices, + ARRAY_SIZE(u8500_hsi_devices)); +#endif + +#ifdef CONFIG_MOP500_NUIB + mop500_nuib_init(); +#endif + platform_add_devices(u8500_platform_devices, + ARRAY_SIZE(u8500_platform_devices)); } -MACHINE_START(U8500, "ST-Ericsson MOP500 platform") - /* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */ +#ifndef CONFIG_MACH_U8500_SNOWBALL +MACHINE_START(U8500, "ST-Ericsson U8500 Platform") + /* Maintainer: ST-Ericsson */ + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = mop500_init_machine, +MACHINE_END +#else +MACHINE_START(SNOWBALL, "ST-Ericsson Snowball board") + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = mop500_init_machine, +MACHINE_END +#endif + +MACHINE_START(NOMADIK, "ST-Ericsson U8500 Platform") + /* Maintainer: ST-Ericsson */ + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = mop500_init_machine, +MACHINE_END + +MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+") + /* Maintainer: ST-Ericsson */ .phys_io = U8500_UART2_BASE, .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, - .boot_params = 0x100, + .boot_params = 0x00000100, .map_io = u8500_map_io, .init_irq = ux500_init_irq, - /* we re-use nomadik timer here */ - .timer = &ux500_timer, - .init_machine = u8500_init_machine, + .timer = &u8500_timer, + .init_machine = mop500_init_machine, MACHINE_END diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h new file mode 100644 index 00000000000..1367eae9637 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __BOARD_MOP500_H +#define __BOARD_MOP500_H + +#define SNOWBALL_SDMMC_EN_GPIO 217 +#define SNOWBALL_SDMMC_1V8_3V_GPIO 228 +#define SNOWBALL_SDMMC_CD_GPIO 218 + +#define HREFV60_TOUCH_RST_GPIO 143 +#define HREFV60_PROX_SENSE_GPIO 217 +#define HREFV60_HAL_SW_GPIO 145 +#define HREFV60_SDMMC_EN_GPIO 169 +#define HREFV60_SDMMC_1V8_3V_GPIO 5 +#define HREFV60_SDMMC_CD_GPIO 95 +#define HREFV60_ACCEL_INT1_GPIO 82 +#define HREFV60_ACCEL_INT2_GPIO 83 +#define HREFV60_MAGNET_DRDY_GPIO 32 +#define HREFV60_DISP1_RST_GPIO 65 +#define HREFV60_DISP2_RST_GPIO 66 +#define HREFV60_MMIO_XENON_CHARGE 170 +#define HREFV60_XSHUTDOWN_SECONDARY_SENSOR 140 +#define XSHUTDOWN_PRIMARY_SENSOR 141 +#define XSHUTDOWN_SECONDARY_SENSOR 142 +struct i2c_board_info; +void mop500_nuib_init(void); +void __init mop500_u8500uib_init(void); +void __init mop500_stuib_init(void); +void mop500_uib_i2c_add(int busnum, struct i2c_board_info const *info, + unsigned n); +void mop500_msp_init(void); +void __init mop500_pins_init(void); + +int msp13_i2s_init(void); +int msp13_i2s_exit(void); + +#endif diff --git a/arch/arm/mach-ux500/board-pdp-mcde.c b/arch/arm/mach-ux500/board-pdp-mcde.c new file mode 100644 index 00000000000..8094be89fef --- /dev/null +++ b/arch/arm/mach-ux500/board-pdp-mcde.c @@ -0,0 +1,621 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/mfd/ab8500/denc.h> +#include <video/av8100.h> +#include <video/mcde_display.h> +#include <video/mcde_display-sony_sy35560_dsi.h> +#include <video/mcde_display-av8100.h> +#include <video/mcde_display-ab8500.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> +#include "pins-db8500.h" +#include "pins.h" + +#define DSI_UNIT_INTERVAL_0 0x9 +#define DSI_UNIT_INTERVAL_1 0x9 +#define DSI_UNIT_INTERVAL_2 0x6 + +#define PRIMARY_DISPLAY_ID 0 +#define SECONDARY_DISPLAY_ID 1 +#define TERTIARY_DISPLAY_ID 2 + +#define ROTATE_MAIN 0 + +static int display_initialized_during_boot; + +static int __init startup_graphics_setup(char *str) +{ + + if (get_option(&str, &display_initialized_during_boot) != 1) + display_initialized_during_boot = 0; + + switch (display_initialized_during_boot) { + case 1: + pr_info("Startup graphics support\n"); + break; + case 0: + default: + pr_info("No startup graphics supported\n"); + break; + }; + + return 1; +} +__setup("startup_graphics=", startup_graphics_setup); + +#ifdef CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY + +static int sony_sy35560_update(struct mcde_display_device *dev) +{ + int ret; + + /* TODO: Dirty */ + if (dev->prepare_for_update) { + /* TODO: Send dirty rectangle */ + ret = dev->prepare_for_update(dev, 0, 0, + dev->native_x_res, dev->native_y_res); + if (ret < 0) { + dev_warn(&dev->dev, + "%s:Failed to prepare for update\n", __func__); + return ret; + } + } + /* TODO: Calculate & set update rect */ + ret = mcde_chnl_update(dev->chnl_state, &dev->update_area); + if (ret < 0) { + dev_warn(&dev->dev, "%s:Failed to update channel\n", __func__); + return ret; + } + if (dev->first_update && dev->on_first_update) + dev->on_first_update(dev); + + if (dev->power_mode != MCDE_DISPLAY_PM_ON && dev->set_power_mode) { + /* need to wait a while before turning on the display */ + mdelay(5); + ret = dev->set_power_mode(dev, MCDE_DISPLAY_PM_ON); + if (ret < 0) { + dev_warn(&dev->dev, + "%s:Failed to set power mode to on\n", + __func__); + return ret; + } + } + + dev_vdbg(&dev->dev, "Overlay updated, chnl=%d\n", dev->chnl_id); + + return 0; +} + +static int sony_sy35560_platform_enable(struct mcde_display_device *dev) +{ + int ret = 0; + struct sony_sy35560_platform_data *pdata = + dev->dev.platform_data; + + dev_info(&dev->dev, "%s: Reset & power on sony display\n", __func__); + + if (pdata->regulator_id) { + ((struct sony_sy35560_device *)dev)->regulator = + regulator_get(NULL, pdata->regulator_id); + if (IS_ERR(((struct sony_sy35560_device *)dev)->regulator)) { + ret = PTR_ERR( + ((struct sony_sy35560_device *)dev)->regulator); + dev_err(&dev->dev, + "%s:Failed to get regulator '%s'\n", + __func__, pdata->regulator_id); + ((struct sony_sy35560_device *)dev)->regulator = NULL; + goto out; + } + regulator_set_voltage( + ((struct sony_sy35560_device *)dev)->regulator, + pdata->min_supply_voltage, + pdata->max_supply_voltage); + ret = regulator_enable( + ((struct sony_sy35560_device *)dev)->regulator); + if (ret < 0) { + dev_err(&dev->dev, + "%s:Failed to enable regulator\n" + , __func__); + goto out; + } + } + + if (!pdata->skip_init) { + dev_info(&dev->dev, + "%s: Startup graphics disabled, doing full init\n", + __func__); + if (pdata->reset_gpio) { + ret = gpio_request(pdata->reset_gpio, NULL); + if (ret) { + dev_warn(&dev->dev, + "%s:Failed to request gpio %d\n", + __func__, pdata->reset_gpio); + goto out; + } + + gpio_direction_output(pdata->reset_gpio, 1); + gpio_set_value(pdata->reset_gpio, 0); + mdelay(1); + gpio_set_value(pdata->reset_gpio, 1); + } + } else { + dev_info(&dev->dev, + "%s: Display already initialized during boot\n", + __func__); + pdata->skip_init = false; + } + + dev->update = sony_sy35560_update; + + /* TODO: Remove when DSI send command uses interrupts */ + dev->prepare_for_update = NULL; + +#ifdef CONFIG_SONY_SY35560_ENABLE_ESD_CHECK + /* add ESD status check to workqueue */ + queue_delayed_work(((struct sony_sy35560_device *)dev)->esd_wq, + &(((struct sony_sy35560_device *)dev)->esd_work), + SONY_SY35560_ESD_CHECK_PERIOD); +#endif + +out: + if (pdata->reset_gpio) + gpio_free(pdata->reset_gpio); + return ret; +} + +static int sony_sy35560_platform_disable(struct mcde_display_device *dev) +{ + dev_info(&dev->dev, "%s: Reset & power off sony display\n", __func__); + + if (((struct sony_sy35560_device *)dev)->regulator) { + if (regulator_disable( + ((struct sony_sy35560_device *)dev)->regulator) < 0) + dev_err(&dev->dev, + "%s:Failed to disable regulator\n", + __func__); + } + return 0; +} + +static struct mcde_port port0 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 0, + .sync_src = MCDE_SYNCSRC_BTA, + .update_auto_trig = false, + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_0, + .clk_cont = false, + }, + }, +}; + +struct sony_sy35560_platform_data sony_sy35560_display0_pdata = { + .reset_gpio = EGPIO_PIN_15, +#ifdef CONFIG_REGULATOR + .regulator_id = "v-display", + .min_supply_voltage = 2800000, /* 2.8V */ + .max_supply_voltage = 2800000 /* 2.8V */ +#endif +}; + +struct sony_sy35560_device sony_sy35560_display0 = { + .base = { + .name = "mcde_disp_sony", + .id = PRIMARY_DISPLAY_ID, + .port = &port0, + .chnl_id = MCDE_CHNL_A, + .fifo = MCDE_FIFO_C0, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 480, + .native_y_res = 854, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC + .synchronized_update = true, +#else + .synchronized_update = false, +#endif + .platform_enable = sony_sy35560_platform_enable, + .platform_disable = sony_sy35560_platform_disable, + /* TODO: Remove rotation buffers once ESRAM driver + * is completed */ + .rotbuf1 = U8500_ESRAM_BASE + 0x20000 * 4, + .rotbuf2 = U8500_ESRAM_BASE + 0x20000 * 4 + 0x10000, + .dev = { + .platform_data = &sony_sy35560_display0_pdata, + }, + } +}; +#endif /* CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY */ + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY +static struct mcde_port subdisplay_port = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 1, + .sync_src = MCDE_SYNCSRC_BTA, + .update_auto_trig = false, + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_1, + .clk_cont = false, + }, + }, + +}; + +static struct mcde_display_generic_platform_data generic_subdisplay_pdata = { + .reset_gpio = EGPIO_PIN_14, + .reset_delay = 1, +#ifdef CONFIG_REGULATOR + .regulator_id = "v-display", + .min_supply_voltage = 2500000, /* 2.5V */ + .max_supply_voltage = 2700000 /* 2.7V */ +#endif +}; + +static struct mcde_display_device generic_subdisplay = { + .name = "mcde_disp_generic_subdisplay", + .id = SECONDARY_DISPLAY_ID, + .port = &subdisplay_port, + .chnl_id = MCDE_CHNL_C1, + .fifo = MCDE_FIFO_C1, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 864, + .native_y_res = 480, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_VSYNC + .synchronized_update = true, +#else + .synchronized_update = false, +#endif + .dev = { + .platform_data = &generic_subdisplay_pdata, + }, +}; +#endif /* CONFIG_DISPLAY_GENERIC_DSI_SECONDARY */ + + +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY +static struct mcde_port port_tvout1 = { + .type = MCDE_PORTTYPE_DPI, + .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP, + .ifc = 0, + .link = 1, /* channel B */ + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, + .phy = { + .dpi = { + .bus_width = 4, /* DDR mode */ + .tv_mode = true, + .clock_div = MCDE_PORT_DPI_NO_CLOCK_DIV, + }, + }, +}; + +static struct ab8500_display_platform_data ab8500_display_pdata = { + .denc_regulator_id = "v-tvout", + .rgb_2_yCbCr_transform = { + .matrix = { + {0x42, 0x81, 0x19}, + {0xffda, 0xffb6, 0x70}, + {0x70, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, + } +}; + +static struct ux500_pins *tvout_pins; + +static int ab8500_platform_enable(struct mcde_display_device *ddev) +{ + int res = 0; + + dev_info(&ddev->dev, "%s\n", __func__); + + if (!tvout_pins) { + tvout_pins = ux500_pins_get("mcde-tvout"); + if (!tvout_pins) + return -EINVAL; + } + + res = ux500_pins_enable(tvout_pins); + if (res != 0) + goto failed; + + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static int ab8500_platform_disable(struct mcde_display_device *ddev) +{ + int res; + + dev_info(&ddev->dev, "%s\n", __func__); + + res = ux500_pins_disable(tvout_pins); + if (res != 0) + goto failed; + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +struct mcde_display_device tvout_ab8500_display = { + .name = "mcde_tv_ab8500", + .id = TERTIARY_DISPLAY_ID, + .port = &port_tvout1, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 720, + .native_y_res = 576, + .dev = { + .platform_data = &ab8500_display_pdata, + }, + + /* + * We might need to describe the std here: + * - there are different PAL / NTSC formats (do they require MCDE + * settings?) + */ + .platform_enable = ab8500_platform_enable, + .platform_disable = ab8500_platform_disable, +}; +#endif /* CONFIG_DISPLAY_AB8500_TERTIARY */ + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +static struct mcde_port port2 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 2, +#ifdef CONFIG_AV8100_HWTRIG_INT + .sync_src = MCDE_SYNCSRC_TE0, +#endif +#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3 + .sync_src = MCDE_SYNCSRC_TE1, +#endif +#ifdef CONFIG_AV8100_HWTRIG_DSI_TE + .sync_src = MCDE_SYNCSRC_TE_POLLING, +#endif +#ifdef CONFIG_AV8100_HWTRIG_NONE + .sync_src = MCDE_SYNCSRC_OFF, +#endif + .update_auto_trig = true, + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_2, + .clk_cont = false, + }, + }, + .hdmi_sdtv_switch = HDMI_SWITCH, +}; + +struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = { + .reset_gpio = 0, + .reset_delay = 1, + .regulator_id = NULL, /* TODO: "display_main" */ + .ddb_id = 1, + .rgb_2_yCbCr_transform = { + .matrix = { + {0x42, 0x81, 0x19}, + {0xffda, 0xffb6, 0x70}, + {0x70, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, + } +}; + +static int av8100_platform_enable(struct mcde_display_device *dev) +{ + int ret; + struct mcde_display_hdmi_platform_data *pdata = + dev->dev.platform_data; + + if (pdata->reset_gpio) + gpio_set_value(pdata->reset_gpio, pdata->reset_high); + if (pdata->regulator) + ret = regulator_enable(pdata->regulator); +alt_func_failed: + return ret; +} + +static int av8100_platform_disable(struct mcde_display_device *dev) +{ + int ret; + struct mcde_display_hdmi_platform_data *pdata = + dev->dev.platform_data; + + if (pdata->reset_gpio) + gpio_set_value(pdata->reset_gpio, !pdata->reset_high); + if (pdata->regulator) + ret = regulator_disable(pdata->regulator); +alt_func_failed: + return ret; +} + +struct mcde_display_device av8100_hdmi = { + .name = "av8100_hdmi", + .id = TERTIARY_DISPLAY_ID, + .port = &port2, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 1280, + .native_y_res = 720, + .synchronized_update = true, + .dev = { + .platform_data = &av8100_hdmi_pdata, + }, + .platform_enable = av8100_platform_enable, + .platform_disable = av8100_platform_disable, +}; +#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */ + +static struct fb_info *fbs[3] = { NULL, NULL, NULL }; +static struct mcde_display_device *displays[3] = { NULL, NULL, NULL }; + +static int display_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = dev; + u16 width, height; + u16 virtual_width, virtual_height; + bool rotate; + + if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) + return 0; + + if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= ARRAY_SIZE(fbs)) + return 0; + + mcde_dss_get_native_resolution(ddev, &width, &height); + + rotate = (ddev->id == 0 && ROTATE_MAIN); + if (rotate) { + u16 tmp = height; + height = width; + width = tmp; + } + + virtual_width = width; + virtual_height = height * 2; + + /* Create frame buffer */ + fbs[ddev->id] = mcde_fb_create(ddev, + width, height, + virtual_width, virtual_height, + ddev->default_pixel_format, + rotate ? FB_ROTATE_CW : FB_ROTATE_UR); + if (IS_ERR(fbs[ddev->id])) + pr_warning("Failed to create fb for display %s\n", ddev->name); + else + pr_info("Framebuffer created (%s)\n", ddev->name); + + return 0; +} + +static struct notifier_block display_nb = { + .notifier_call = display_postregistered_callback, +}; + +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + u8 *addr; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + if (mfb->id == 0 && display_initialized_during_boot) + goto out; + + + var = info->var; + fix = info->fix; + addr = ioremap(fix.smem_start, + var.yres_virtual * fix.line_length); + memset(addr, 0x00, + var.yres_virtual * fix.line_length); + var.yoffset = var.yoffset ? 0 : var.yres; + if (info->fbops->fb_pan_display) + ret = info->fbops->fb_pan_display(&var, info); +out: + return ret; +} + +static struct notifier_block framebuffer_nb = { + .notifier_call = framebuffer_postregistered_callback, +}; + +int __init init_display_devices(void) +{ + int ret; + + ret = fb_register_client(&framebuffer_nb); + if (ret) + pr_warning("Failed to register framebuffer notifier\n"); + + ret = mcde_dss_register_notifier(&display_nb); + if (ret) + pr_warning("Failed to register dss notifier\n"); + +#ifdef CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY + /* TODO: enable this code if uboot graphics should be used + if (display_initialized_during_boot) + ((struct sony_sy35560_platform_data *)sony_sy35560_display0. + base.dev.platform_data)->skip_init = true; + */ + ret = mcde_display_device_register( + (struct mcde_display_device *)&sony_sy35560_display0); + if (ret) + pr_warning("Failed to register Sony sy35560 display device 0\n"); + displays[0] = (struct mcde_display_device *)&sony_sy35560_display0; +#endif + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY + ret = mcde_display_device_register(&generic_subdisplay); + if (ret) + pr_warning("Failed to register generic sub display device\n"); + displays[1] = &generic_subdisplay; +#endif + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY + ret = mcde_display_device_register(&av8100_hdmi); + if (ret) + pr_warning("Failed to register av8100_hdmi\n"); + displays[2] = &av8100_hdmi; +#endif +#ifdef CONFIG_DISPLAY_AB8500_TERTIARY + ret = platform_device_register(&ab8500_denc); + if (ret) + pr_warning("Failed to register ab8500_denc device\n"); + else { + ret = mcde_display_device_register(&tvout_ab8500_display); + if (ret) + pr_warning("Failed to register ab8500 tvout device\n"); + displays[2] = &tvout_ab8500_display; + } +#endif + + return ret; +} + +module_init(init_display_devices); diff --git a/arch/arm/mach-ux500/board-snowball-digio.c b/arch/arm/mach-ux500/board-snowball-digio.c new file mode 100644 index 00000000000..b8fc1c033b7 --- /dev/null +++ b/arch/arm/mach-ux500/board-snowball-digio.c @@ -0,0 +1,118 @@ + +/* + * This defines the user led (output) and 4-keys gpio keyboard (input) + * Original code by Gregory Hermant + * Split to a standalone file by Alessandro Rubini + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/leds.h> +#include <plat/pincfg.h> +#include <plat/gpio.h> +#include "pins-db5500.h" + +static pin_cfg_t snowball_pins[] = { + PIN_CFG(32, GPIO) | PIN_INPUT_PULLUP, /* led */ + PIN_CFG(151, GPIO) | PIN_INPUT_PULLUP, /* button */ + PIN_CFG(152, GPIO) | PIN_INPUT_PULLUP, /* button */ +/* PIN_CFG(161, GPIO) | PIN_INPUT_PULLUP, button */ + PIN_CFG(162, GPIO) | PIN_INPUT_PULLUP, /* button */ +}; + +static struct gpio_led snowball_led_array[] = { + { + .name = "user_led", + .default_trigger = "none", + .gpio = 142, + }, +}; + +static struct gpio_led_platform_data snowball_led_data = { + .leds = snowball_led_array, + .num_leds = ARRAY_SIZE(snowball_led_array), +}; + +static struct platform_device snowball_led_dev = { + .name = "leds-gpio", + .dev = { + .platform_data = &snowball_led_data, + }, +}; + +static struct gpio_keys_button snowball_key_array[] = { + { + .gpio = 32, + .type = EV_KEY, + .code = KEY_1, + .desc = "userpb", + .active_low = 1, + .debounce_interval = 50, + .wakeup = 1, + }, + { + .gpio = 151, + .type = EV_KEY, + .code = KEY_2, + .desc = "extkb1", + .active_low = 1, + .debounce_interval = 50, + .wakeup = 1, + }, + { + .gpio = 152, + .type = EV_KEY, + .code = KEY_3, + .desc = "extkb2", + .active_low = 1, + .debounce_interval = 50, + .wakeup = 1, + }, + /* + { + .gpio = 161, + .type = EV_KEY, + .code = KEY_4, + .desc = "extkb3", + .active_low = 1, + .debounce_interval = 50, + .wakeup = 1, + }, + */ + { + .gpio = 162, + .type = EV_KEY, + .code = KEY_5, + .desc = "extkb4", + .active_low = 1, + .debounce_interval = 50, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data snowball_key_data = { + .buttons = snowball_key_array, + .nbuttons = ARRAY_SIZE(snowball_key_array), +}; + +static struct platform_device snowball_key_dev = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &snowball_key_data, + } +}; + +static int snowball_digio_init(void) +{ + nmk_config_pins(snowball_pins, ARRAY_SIZE(snowball_pins)); + platform_device_register(&snowball_led_dev); + platform_device_register(&snowball_key_dev); + return 0; +} + +module_init(snowball_digio_init); + +/* no release function: I'm lazy at this point */ diff --git a/arch/arm/mach-ux500/board-snowball-netdev.c b/arch/arm/mach-ux500/board-snowball-netdev.c new file mode 100644 index 00000000000..48404e4f953 --- /dev/null +++ b/arch/arm/mach-ux500/board-snowball-netdev.c @@ -0,0 +1,74 @@ +#include <linux/module.h> +#include <linux/resource.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> +#include <mach/irqs.h> +#include <asm/io.h> + +struct smsc911x_platform_config sbnet_cfg = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .shift = 1, + .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, +}; + +struct resource sbnet_res[] = { + { + .name = "smsc911x-memory", + .start = (0x5000 << 16), + .end = (0x5000 << 16) + 0x3ff, + .flags = IORESOURCE_MEM, + },{ + .start = GPIO_TO_IRQ(140), + .end = GPIO_TO_IRQ(140), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, + }, +}; + +struct platform_device sbnet_dev = { + .name = "smsc911x", + .num_resources = ARRAY_SIZE(sbnet_res), + .resource = sbnet_res, + .dev = { + .platform_data = &sbnet_cfg, + }, +}; + +int sbnet_init(void) +{ + volatile u32 *ptr = ioremap(0x80000000, 0x10000); + + if (!machine_is_snowball()) { + printk("no netdev: no snowball\n"); + return 0; + } + printk("init netdev: is snowball\n"); + + /* + * Horribly, fix all the configuration by hand + */ + /* Turn on the FSMC device */ + *(ptr + 0xf000 / 4) = 1; + *(ptr + 0xf008 / 4) = 1; + + /* Configure the FSMC device */ + *(ptr + 0x0000 / 4) = 0x0000305b; + *(ptr + 0x0004 / 4) = 0x01010110; + + /* Fix some gpio bits */ + *(ptr + 0xe120 / 4) &= ~0x7f8; + *(ptr + 0xe124 / 4) |= 0x7f8; + iounmap(ptr); + + return platform_device_register(&sbnet_dev); +} + +void sbnet_exit(void) +{ + platform_device_unregister(&sbnet_dev); +} + +module_init(sbnet_init); +module_exit(sbnet_exit); + +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ux500/board-snowball-pins.c b/arch/arm/mach-ux500/board-snowball-pins.c new file mode 100644 index 00000000000..45ff0803f71 --- /dev/null +++ b/arch/arm/mach-ux500/board-snowball-pins.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011-2012 ST-Ericsson + * + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> + +#include <plat/pincfg.h> + +#include <mach/hardware.h> + +#include "pins-db8500.h" + +static pin_cfg_t snowball_pins[] = { + /* I2C */ + GPIO147_I2C0_SCL, + GPIO148_I2C0_SDA, + GPIO16_I2C1_SCL, + GPIO17_I2C1_SDA, + GPIO10_I2C2_SDA, + GPIO11_I2C2_SCL, + GPIO229_I2C3_SDA, + GPIO230_I2C3_SCL, + + /* SSP0, to AB8500 */ + GPIO143_SSP0_CLK, + GPIO144_SSP0_FRM, + GPIO145_SSP0_RXD | PIN_PULL_DOWN, + GPIO146_SSP0_TXD, + + /* MSP0: BT */ + GPIO12_MSP0_TXD, + GPIO13_MSP0_TFS, + GPIO14_MSP0_TCK, + GPIO15_MSP0_RXD, + + /* MSP2: HDMI */ + GPIO193_MSP2_TXD, + GPIO194_MSP2_TCK, + GPIO195_MSP2_TFS, + GPIO196_MSP2_RXD | PIN_OUTPUT_LOW, + + /* MMC0: MicroSD card */ + GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH, + GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH, + GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH, + GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH, + GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL, + GPIO23_MC0_CLK | PIN_OUTPUT_LOW, + GPIO24_MC0_CMD | PIN_INPUT_PULLUP, + GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP, + GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP, + GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP, + GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP, + + /* SDI1: WLAN */ + GPIO208_MC1_CLK | PIN_OUTPUT_LOW, + GPIO209_MC1_FBCLK | PIN_INPUT_NOPULL, + GPIO210_MC1_CMD | PIN_INPUT_PULLUP, + GPIO211_MC1_DAT0 | PIN_INPUT_PULLUP, + GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP, + GPIO213_MC1_DAT2 | PIN_INPUT_PULLUP, + GPIO214_MC1_DAT3 | PIN_INPUT_PULLUP, + + /* MMC2: LAN */ + GPIO86_SM_ADQ0, + GPIO87_SM_ADQ1, + GPIO88_SM_ADQ2, + GPIO89_SM_ADQ3, + GPIO90_SM_ADQ4, + GPIO91_SM_ADQ5, + GPIO92_SM_ADQ6, + GPIO93_SM_ADQ7, + + GPIO94_SM_ADVn, + GPIO95_SM_CS0n, + GPIO96_SM_OEn, + GPIO97_SM_WEn, + + GPIO128_SM_CKO, + GPIO130_SM_FBCLK, + GPIO131_SM_ADQ8, + GPIO132_SM_ADQ9, + GPIO133_SM_ADQ10, + GPIO134_SM_ADQ11, + GPIO135_SM_ADQ12, + GPIO136_SM_ADQ13, + GPIO137_SM_ADQ14, + GPIO138_SM_ADQ15, + + /* RSTn_LAN */ + GPIO141_GPIO | PIN_OUTPUT_HIGH, + + /* MMC4: eMMC */ + GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP, + GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP, + GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP, + GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP, + GPIO201_MC4_CMD | PIN_INPUT_PULLUP, + GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL, + GPIO203_MC4_CLK | PIN_OUTPUT_LOW, + GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP, + GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP, + GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP, + GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP, + + GPIO141_GPIO | PIN_OUTPUT_HIGH, /* RSTn_LAN */ + + /* UART: WLAN */ + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH, + + /* UART: DBG port */ + GPIO29_U2_RXD | PIN_INPUT_PULLUP, + GPIO30_U2_TXD | PIN_OUTPUT_HIGH, + GPIO31_U2_CTSn | PIN_INPUT_PULLUP, + GPIO32_U2_RTSn | PIN_OUTPUT_HIGH, +}; + +/* + * This function is called to force gpio power save + * settings during suspend. + * This is a temporary solution until all drivers are + * controlling their pin settings when in inactive mode. + * + * Made empty for Snowball + */ +void mop500_pins_suspend_force(void) +{ + return; +} + +/* + * This function is called to force gpio power save + * mux settings during suspend. + * This is a temporary solution until all drivers are + * controlling their pin settings when in inactive mode. + */ +void mop500_pins_suspend_force_mux(void) +{ + return; +} + +void __init snowball_pins_init(void) +{ + nmk_config_pins(snowball_pins, + ARRAY_SIZE(snowball_pins)); +} diff --git a/arch/arm/mach-ux500/board-snowball.c b/arch/arm/mach-ux500/board-snowball.c new file mode 100644 index 00000000000..c7d785fb1d6 --- /dev/null +++ b/arch/arm/mach-ux500/board-snowball.c @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2011-2012 ST-Ericsson + * + * Author: Mathieu Poirier <mathieu.poirier@linaro.org>, based on the + * work of Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> in + * board-mop500.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/amba/pl022.h> +#include <linux/interrupt.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/hsi.h> +#include <linux/i2s/i2s.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/stmpe.h> +#include <linux/mfd/tc35892.h> +#include <linux/i2c/lp5521.h> +#include <linux/power_supply.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/ab8500.h> +#include <linux/input/bu21013.h> +#include <linux/spi/stm_msp.h> +#include <linux/leds_pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/mfd/ab8500/ab8500-bm.h> +#include <linux/mfd/ab8500/denc.h> +#include <linux/ste_timed_vibra.h> +#include <linux/mfd/ab8500/ab8500-gpio.h> +#include <linux/mfd/cg2900.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> + +#include <plat/pincfg.h> +#include <plat/ske.h> +#include <plat/i2c.h> + +#include <mach/devices.h> +#include <mach/sensors1p.h> +#include <mach/ste_audio_io.h> +#include <mach/setup.h> +#include <mach/tc35893-keypad.h> +#include <mach/ste_audio_io_vibrator.h> +#include <video/av8100.h> +#include <mach/devices.h> +#include <mach/irqs.h> +#include <mach/ste-dma40-db8500.h> + +#include "devices-cg2900.h" +#include "devices-db8500.h" +#include "board-mop500-regulators.h" +#include "regulator-u8500.h" +#include "pins-db8500.h" +#include "board-snowball.h" + +static struct av8100_platform_data av8100_plat_data = { + .irq = GPIO_TO_IRQ(192), + .reset = 196, + .regulator_pwr_id = "hdmi_1v8", +}; + +static struct i2c_board_info __initdata mop500_i2c0_devices[] = { + { + I2C_BOARD_INFO("av8100", 0x70), + .platform_data = &av8100_plat_data, + }, +}; +static struct i2c_board_info __initdata mop500_i2c1_devices[] = {}; +static struct i2c_board_info __initdata mop500_i2c2_devices[] = {}; +static struct i2c_board_info __initdata mop500_i2c3_devices[] = {}; + +/* + * MSP-SPI + */ + +#define NUM_MSP_CLIENTS 10 + +static struct stm_msp_controller mop500_msp2_spi_data = { + .id = MSP_2_CONTROLLER, + .num_chipselect = NUM_MSP_CLIENTS, + .base_addr = U8500_MSP2_BASE, + .device_name = "msp2", +}; + +/* + * SSP + */ + +#define NUM_SSP_CLIENTS 10 + +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg ssp0_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV8_SSP0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg ssp0_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV8_SSP0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct pl022_ssp_controller mop500_ssp0_data = { + .bus_id = SSP_0_CONTROLLER, + .num_chipselect = NUM_SSP_CLIENTS, +#ifdef CONFIG_STE_DMA40 + .enable_dma = 1, + .dma_filter = stedma40_filter, + .dma_rx_param = &ssp0_dma_cfg_rx, + .dma_tx_param = &ssp0_dma_cfg_tx, +#endif + +}; + +#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm) \ +static struct nmk_i2c_controller mop500_i2c##id##_data = { \ + /* \ + * slave data setup time, which is \ + * 250 ns,100ns,10ns which is 14,6,2 \ + * respectively for a 48 Mhz \ + * i2c clock \ + */ \ + .slsu = _slsu, \ + /* Tx FIFO threshold */ \ + .tft = _tft, \ + /* Rx FIFO threshold */ \ + .rft = _rft, \ + /* std. mode operation */ \ + .clk_freq = clk, \ + /* Slave response timeout(ms) */\ + .timeout = t_out, \ + .sm = _sm, \ +} + +/* + * The board uses 4 i2c controllers, initialize all of + * them with slave data setup time of 250 ns, + * Tx & Rx FIFO threshold values as 1 and standard + * mode of operation + */ +U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); +U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, 500, I2C_FREQ_MODE_FAST); + +static struct hsi_board_info __initdata stm_hsi_devices[] = { + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0, + .chan_num = 0, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1, + .chan_num = 0, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0, + .chan_num = 1, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1, + .chan_num = 1, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0, + .chan_num = 2, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1, + .chan_num = 2, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0, + .chan_num = 3, .mode = 1}, + {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1, + .chan_num = 3, .mode = 1}, +}; + +#ifdef CONFIG_AB8500_GPIO +static struct ab8500_gpio_platform_data ab8500_gpio_pdata = { + .gpio_base = AB8500_PIN_GPIO1, + /* config_reg is the initial configuration of ab8500 pins. + * The pins can be configured as GPIO or alt functions based + * on value present in GpioSel1 to GpioSel6 and AlternatFunction + * register. This is the array of 7 configuration settings. + * One has to compile time decide these settings. Below is the + * explaination of these setting + * GpioSel1 = 0x00 => Pins GPIO1 to GPIO8 are not used as GPIO + * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO + * GpioSel3 = 0x80 => Pin GPIO24 is configured as GPIO + * GpioSel4 = 0x01 => Pin GPIo25 is configured as GPIO + * GpioSel5 = 0x7A => Pins GPIO34, GPIO36 to GPIO39 are conf as GPIO + * GpioSel6 = 0x00 => Pins GPIo41 & GPIo42 are not configured as GPIO + * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured + * as GPIO then this register selectes the alternate fucntions + */ + .config_reg = {0x00, 0x1E, 0x80, 0x01, + 0x7A, 0x00, 0x00}, +}; +#endif + +static struct regulator_init_data *u8500_regulators[U8500_NUM_REGULATORS] = { + [U8500_REGULATOR_VAPE] = &u8500_vape_regulator, + [U8500_REGULATOR_VARM] = &u8500_varm_regulator, + [U8500_REGULATOR_VMODEM] = &u8500_vmodem_regulator, + [U8500_REGULATOR_VPLL] = &u8500_vpll_regulator, + [U8500_REGULATOR_VSMPS1] = &u8500_vsmps1_regulator, + [U8500_REGULATOR_VSMPS2] = &u8500_vsmps2_regulator, + [U8500_REGULATOR_VSMPS3] = &u8500_vsmps3_regulator, + [U8500_REGULATOR_VRF1] = &u8500_vrf1_regulator, + [U8500_REGULATOR_SWITCH_SVAMMDSP] = &u8500_svammdsp_regulator, + [U8500_REGULATOR_SWITCH_SVAMMDSPRET] = &u8500_svammdspret_regulator, + [U8500_REGULATOR_SWITCH_SVAPIPE] = &u8500_svapipe_regulator, + [U8500_REGULATOR_SWITCH_SIAMMDSP] = &u8500_siammdsp_regulator, + [U8500_REGULATOR_SWITCH_SIAMMDSPRET] = &u8500_siammdspret_regulator, + [U8500_REGULATOR_SWITCH_SIAPIPE] = &u8500_siapipe_regulator, + [U8500_REGULATOR_SWITCH_SGA] = &u8500_sga_regulator, + [U8500_REGULATOR_SWITCH_B2R2_MCDE] = &u8500_b2r2_mcde_regulator, + [U8500_REGULATOR_SWITCH_ESRAM12] = &u8500_esram12_regulator, + [U8500_REGULATOR_SWITCH_ESRAM12RET] = &u8500_esram12ret_regulator, + [U8500_REGULATOR_SWITCH_ESRAM34] = &u8500_esram34_regulator, + [U8500_REGULATOR_SWITCH_ESRAM34RET] = &u8500_esram34ret_regulator, +}; + +static struct platform_device u8500_regulator_dev = { + .name = "u8500-regulators", + .id = 0, + .dev = { + .platform_data = u8500_regulators, + }, +}; + +static struct ab8500_audio_platform_data ab8500_audio_plat_data = { + .ste_gpio_altf_init = msp13_i2s_init, + .ste_gpio_altf_exit = msp13_i2s_exit, +}; + +/* + * NOTE! The regulator configuration below must be in exactly the same order as + * the regulator description in the driver, see drivers/regulator/ab8500.c + */ +static struct ab8500_platform_data ab8500_platdata = { + .irq_base = MOP500_AB8500_IRQ_BASE, + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), + .audio = &ab8500_audio_plat_data, +#ifdef CONFIG_AB8500_GPIO + .gpio = &ab8500_gpio_pdata, +#endif +}; + +static struct resource ab8500_resources[] = { + [0] = { + .start = IRQ_DB8500_AB8500, + .end = IRQ_DB8500_AB8500, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device ux500_ab8500_device = { + .name = "ab8500-i2c", + .id = 0, + .dev = { + .platform_data = &ab8500_platdata, + }, + .num_resources = 1, + .resource = ab8500_resources, +}; + +#ifdef CONFIG_MFD_CG2900 +#define CG2900_BT_ENABLE_GPIO 170 +#define CG2900_GBF_ENA_RESET_GPIO 171 +#define CG2900_BT_CTS_GPIO 0 + +enum cg2900_gpio_pull_sleep cg2900_sleep_gpio[21] = { + CG2900_NO_PULL, /* GPIO 0: PTA_CONFX */ + CG2900_PULL_DN, /* GPIO 1: PTA_STATUS */ + CG2900_NO_PULL, /* GPIO 2: UART_CTSN */ + CG2900_PULL_UP, /* GPIO 3: UART_RTSN */ + CG2900_PULL_UP, /* GPIO 4: UART_TXD */ + CG2900_NO_PULL, /* GPIO 5: UART_RXD */ + CG2900_PULL_DN, /* GPIO 6: IOM_DOUT */ + CG2900_NO_PULL, /* GPIO 7: IOM_FSC */ + CG2900_NO_PULL, /* GPIO 8: IOM_CLK */ + CG2900_NO_PULL, /* GPIO 9: IOM_DIN */ + CG2900_PULL_DN, /* GPIO 10: PWR_REQ */ + CG2900_PULL_DN, /* GPIO 11: HOST_WAKEUP */ + CG2900_PULL_DN, /* GPIO 12: IIS_DOUT */ + CG2900_NO_PULL, /* GPIO 13: IIS_WS */ + CG2900_NO_PULL, /* GPIO 14: IIS_CLK */ + CG2900_NO_PULL, /* GPIO 15: IIS_DIN */ + CG2900_PULL_DN, /* GPIO 16: PTA_FREQ */ + CG2900_PULL_DN, /* GPIO 17: PTA_RF_ACTIVE */ + CG2900_NO_PULL, /* GPIO 18: NotConnected (J6428) */ + CG2900_NO_PULL, /* GPIO 19: EXT_DUTY_CYCLE */ + CG2900_NO_PULL, /* GPIO 20: EXT_FRM_SYNCH */ +}; + +static struct platform_device ux500_cg2900_device = { + .name = "cg2900", +}; + +#ifdef CONFIG_MFD_CG2900_CHIP +static struct platform_device ux500_cg2900_chip_device = { + .name = "cg2900-chip", + .dev = { + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_CG2900_CHIP */ + +#ifdef CONFIG_MFD_STLC2690_CHIP +static struct platform_device ux500_stlc2690_chip_device = { + .name = "stlc2690-chip", + .dev = { + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_STLC2690_CHIP */ + +#ifdef CONFIG_MFD_CG2900_TEST +static struct cg2900_platform_data cg2900_test_platform_data = { + .bus = HCI_VIRTUAL, + .gpio_sleep = cg2900_sleep_gpio, +}; + +static struct platform_device ux500_cg2900_test_device = { + .name = "cg2900-test", + .dev = { + .parent = &ux500_cg2900_device.dev, + .platform_data = &cg2900_test_platform_data, + }, +}; +#endif /* CONFIG_MFD_CG2900_TEST */ + +#ifdef CONFIG_MFD_CG2900_UART +static struct resource cg2900_uart_resources[] = { + { + .start = CG2900_GBF_ENA_RESET_GPIO, + .end = CG2900_GBF_ENA_RESET_GPIO, + .flags = IORESOURCE_IO, + .name = "gbf_ena_reset", + }, + { + .start = CG2900_BT_ENABLE_GPIO, + .end = CG2900_BT_ENABLE_GPIO, + .flags = IORESOURCE_IO, + .name = "bt_enable", + }, + { + .start = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .end = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .flags = IORESOURCE_IRQ, + .name = "cts_irq", + }, +}; + +static pin_cfg_t cg2900_uart_enabled[] = { + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH +}; + +static pin_cfg_t cg2900_uart_disabled[] = { + GPIO0_GPIO | PIN_INPUT_PULLUP, /* CTS pull up. */ + GPIO1_GPIO | PIN_OUTPUT_HIGH, /* RTS high-flow off. */ + GPIO2_GPIO | PIN_INPUT_PULLUP, /* RX pull down. */ + GPIO3_GPIO | PIN_OUTPUT_LOW /* TX low - break on. */ +}; + +static struct cg2900_platform_data cg2900_uart_platform_data = { + .bus = HCI_UART, + .gpio_sleep = cg2900_sleep_gpio, + .uart = { + .n_uart_gpios = 4, + .uart_enabled = cg2900_uart_enabled, + .uart_disabled = cg2900_uart_disabled, + }, +}; + +static struct platform_device ux500_cg2900_uart_device = { + .name = "cg2900-uart", + .dev = { + .platform_data = &cg2900_uart_platform_data, + .parent = &ux500_cg2900_device.dev, + }, + .num_resources = ARRAY_SIZE(cg2900_uart_resources), + .resource = cg2900_uart_resources, +}; +#endif /* CONFIG_MFD_CG2900_UART */ +#endif /* CONFIG_MFD_CG2900 */ + +static struct platform_device *u8500_platform_devices[] __initdata = { + /*TODO - add platform devices here */ +}; + +static struct platform_device *platform_devs[] __initdata = { + &u8500_hsit_device, + &u8500_hsir_device, + &u8500_shrm_device, + &ux500_musb_device, + &ux500_hwmem_device, + &ux500_mcde_device, + &ux500_b2r2_device, +}; + +static void __init mop500_i2c_init(void) +{ + db8500_add_i2c0(&mop500_i2c0_data); + db8500_add_i2c1(&mop500_i2c1_data); + db8500_add_i2c2(&mop500_i2c2_data); + db8500_add_i2c3(&mop500_i2c3_data); + + i2c_register_board_info(0, ARRAY_AND_SIZE(mop500_i2c0_devices)); + i2c_register_board_info(1, ARRAY_AND_SIZE(mop500_i2c1_devices)); + i2c_register_board_info(2, ARRAY_AND_SIZE(mop500_i2c2_devices)); + i2c_register_board_info(3, ARRAY_AND_SIZE(mop500_i2c3_devices)); +} + +static void __init mop500_spi_init(void) +{ + db8500_add_ssp0(&mop500_ssp0_data); + db8500_add_msp2_spi(&mop500_msp2_spi_data); +} + +static void __init mop500_uart_init(void) +{ + db8500_add_uart0(); + db8500_add_uart1(); + db8500_add_uart2(); +} + +static void __init mop500_init_machine(void) +{ +#ifdef CONFIG_REGULATOR + platform_device_register(&u8500_regulator_dev); +#endif + + u8500_init_devices(); + + platform_add_devices(platform_devs, + ARRAY_SIZE(platform_devs)); + + snowball_pins_init(); + + platform_device_register(&ux500_ab8500_device); + +#ifdef CONFIG_MFD_CG2900 +#ifdef CONFIG_MFD_CG2900_TEST + dcg2900_init_platdata(&cg2900_test_platform_data); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_UART + dcg2900_init_platdata(&cg2900_uart_platform_data); +#endif /* CONFIG_MFD_CG2900_UART */ + + platform_device_register(&ux500_cg2900_device); +#ifdef CONFIG_MFD_CG2900_UART + platform_device_register(&ux500_cg2900_uart_device); +#endif /* CONFIG_MFD_CG2900_UART */ +#ifdef CONFIG_MFD_CG2900_TEST + platform_device_register(&ux500_cg2900_test_device); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_CHIP + platform_device_register(&ux500_cg2900_chip_device); +#endif /* CONFIG_MFD_CG2900_CHIP */ +#ifdef CONFIG_MFD_STLC2690_CHIP + platform_device_register(&ux500_stlc2690_chip_device); +#endif /* CONFIG_MFD_STLC2690_CHIP */ +#endif /* CONFIG_MFD_CG2900 */ + + mop500_i2c_init(); + mop500_msp_init(); + mop500_spi_init(); + mop500_uart_init(); + + hsi_register_board_info(stm_hsi_devices, ARRAY_SIZE(stm_hsi_devices)); + + platform_add_devices(u8500_platform_devices, + ARRAY_SIZE(u8500_platform_devices)); +} + +MACHINE_START(SNOWBALL, "ST-Ericsson Snowball board") + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = mop500_init_machine, +MACHINE_END diff --git a/arch/arm/mach-ux500/board-snowball.h b/arch/arm/mach-ux500/board-snowball.h new file mode 100644 index 00000000000..d8bd2cd4ed2 --- /dev/null +++ b/arch/arm/mach-ux500/board-snowball.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SNOWBALL_H +#define __SNOWBALL_H + +#define SNOWBALL_SDMMC_EN_GPIO 217 +#define SNOWBALL_SDMMC_1V8_3V_GPIO 228 +#define SNOWBALL_SDMMC_CD_GPIO 218 + +void mop500_msp_init(void); +void __init snowball_pins_init(void); + +int msp13_i2s_init(void); +int msp13_i2s_exit(void); + +#endif diff --git a/arch/arm/mach-ux500/board-svp5500.c b/arch/arm/mach-ux500/board-svp5500.c new file mode 100644 index 00000000000..61477e93ef5 --- /dev/null +++ b/arch/arm/mach-ux500/board-svp5500.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/gpio.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/pincfg.h> + +#include <mach/devices.h> +#include <mach/setup.h> + +#include "pins-db5500.h" +#include "devices-db5500.h" + +static pin_cfg_t svp5500_pins[] = { + GPIO28_U0_TXD, + GPIO29_U0_RXD, +}; + +static void __init svp5500_init_machine(void) +{ + u5500_init_devices(); + + nmk_config_pins(ARRAY_AND_SIZE(svp5500_pins)); + + db5500_add_uart0(); +} + +MACHINE_START(SVP5500, "ST-Ericsson U5500 Simulator") + .phys_io = U5500_UART0_BASE, + .io_pg_offst = (IO_ADDRESS(U5500_UART0_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u5500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = svp5500_init_machine, +MACHINE_END diff --git a/arch/arm/mach-ux500/board-svp8500.c b/arch/arm/mach-ux500/board-svp8500.c new file mode 100644 index 00000000000..78a7842b77e --- /dev/null +++ b/arch/arm/mach-ux500/board-svp8500.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/pincfg.h> + +#include <mach/devices.h> +#include <mach/hardware.h> +#include <mach/setup.h> + +#include "devices-db8500.h" +#include "pins-db8500.h" + +static pin_cfg_t svp8500_pins[] = { + /* UART */ + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH, + GPIO4_U1_RXD | PIN_INPUT_PULLUP, + GPIO5_U1_TXD | PIN_OUTPUT_HIGH, + GPIO6_U1_CTSn | PIN_INPUT_PULLUP, + GPIO7_U1_RTSn | PIN_OUTPUT_HIGH, + GPIO29_U2_RXD | PIN_INPUT_PULLUP, + GPIO30_U2_TXD | PIN_OUTPUT_HIGH, + GPIO31_U2_CTSn | PIN_INPUT_PULLUP, + GPIO32_U2_RTSn | PIN_OUTPUT_HIGH, +}; + +static void __init svp8500_uart_init(void) +{ + db8500_add_uart0(NULL); + db8500_add_uart1(); + db8500_add_uart2(); +} + +static void __init svp8500_init_machine(void) +{ + nmk_config_pins(ARRAY_AND_SIZE(svp8500_pins)); + + svp8500_uart_init(); +} + +MACHINE_START(SVP8500V1, "ST-Ericsson U8500 Simulator (V1)") + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = svp8500_init_machine, +MACHINE_END + +MACHINE_START(SVP8500V2, "ST-Ericsson U8500 Simulator (V2)") + .phys_io = U8500_UART2_BASE, + .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = svp8500_init_machine, +MACHINE_END diff --git a/arch/arm/mach-ux500/board-u5500-cg2900.c b/arch/arm/mach-ux500/board-u5500-cg2900.c new file mode 100644 index 00000000000..a96d7743343 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-cg2900.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/platform_device.h> +#include <linux/mfd/cg2900.h> +#include <linux/gpio.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci.h> + +#include <plat/gpio.h> +#include <plat/pincfg.h> + +#include "devices-cg2900.h" +#include "pins-db5500.h" + +#define CG2900_BT_CTS_GPIO 168 + +enum cg2900_gpio_pull_sleep cg2900_sleep_gpio[21] = { + CG2900_NO_PULL, /* GPIO 0: PTA_CONFX */ + CG2900_PULL_DN, /* GPIO 1: PTA_STATUS */ + CG2900_NO_PULL, /* GPIO 2: UART_CTSN */ + CG2900_PULL_UP, /* GPIO 3: UART_RTSN */ + CG2900_PULL_UP, /* GPIO 4: UART_TXD */ + CG2900_NO_PULL, /* GPIO 5: UART_RXD */ + CG2900_PULL_DN, /* GPIO 6: IOM_DOUT */ + CG2900_NO_PULL, /* GPIO 7: IOM_FSC */ + CG2900_NO_PULL, /* GPIO 8: IOM_CLK */ + CG2900_NO_PULL, /* GPIO 9: IOM_DIN */ + CG2900_PULL_DN, /* GPIO 10: PWR_REQ */ + CG2900_PULL_DN, /* GPIO 11: HOST_WAKEUP */ + CG2900_PULL_DN, /* GPIO 12: IIS_DOUT */ + CG2900_NO_PULL, /* GPIO 13: IIS_WS */ + CG2900_NO_PULL, /* GPIO 14: IIS_CLK */ + CG2900_NO_PULL, /* GPIO 15: IIS_DIN */ + CG2900_PULL_DN, /* GPIO 16: PTA_FREQ */ + CG2900_PULL_DN, /* GPIO 17: PTA_RF_ACTIVE */ + CG2900_NO_PULL, /* GPIO 18: NotConnected (J6428) */ + CG2900_NO_PULL, /* GPIO 19: EXT_DUTY_CYCLE */ + CG2900_NO_PULL, /* GPIO 20: EXT_FRM_SYNCH */ +}; + +static struct platform_device ux500_cg2900_device = { + .name = "cg2900", +}; + +#ifdef CONFIG_MFD_CG2900_CHIP +static struct platform_device ux500_cg2900_chip_device = { + .name = "cg2900-chip", + .dev = { + .parent = &ux500_cg2900_device.dev, + }, +}; +#endif /* CONFIG_MFD_CG2900_CHIP */ + +#ifdef CONFIG_MFD_CG2900_TEST +static struct cg2900_platform_data cg2900_test_platform_data = { + .bus = HCI_VIRTUAL, + .gpio_sleep = cg2900_sleep_gpio, +}; + +static struct platform_device ux500_cg2900_test_device = { + .name = "cg2900-test", + .dev = { + .parent = &ux500_cg2900_device.dev, + .platform_data = &cg2900_test_platform_data, + }, +}; +#endif /* CONFIG_MFD_CG2900_TEST */ + +#ifdef CONFIG_MFD_CG2900_UART +static struct resource cg2900_uart_resources[] = { + { + .start = CG2900_BT_CTS_GPIO, + .end = CG2900_BT_CTS_GPIO, + .flags = IORESOURCE_IO, + .name = "cts_gpio", + }, + { + .start = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .end = GPIO_TO_IRQ(CG2900_BT_CTS_GPIO), + .flags = IORESOURCE_IRQ, + .name = "cts_irq", + }, +}; + +static pin_cfg_t cg2900_uart_enabled[] = { + GPIO165_U3_RXD | PIN_INPUT_PULLUP, + GPIO166_U3_TXD | PIN_OUTPUT_HIGH, + GPIO167_U3_RTSn | PIN_OUTPUT_HIGH, + GPIO168_U3_CTSn | PIN_INPUT_PULLUP, +}; + +static pin_cfg_t cg2900_uart_disabled[] = { + GPIO165_GPIO | PIN_INPUT_PULLUP, /* RX pull down. */ + GPIO166_GPIO | PIN_OUTPUT_LOW, /* TX low - break on. */ + GPIO167_GPIO | PIN_OUTPUT_HIGH, /* RTS high-flow off. */ + GPIO168_GPIO | PIN_INPUT_PULLUP, /* CTS pull up. */ +}; + +static struct cg2900_platform_data cg2900_uart_platform_data = { + .bus = HCI_UART, + .gpio_sleep = cg2900_sleep_gpio, + .uart = { + .n_uart_gpios = 4, + .uart_enabled = cg2900_uart_enabled, + .uart_disabled = cg2900_uart_disabled, + }, +}; + +static struct platform_device ux500_cg2900_uart_device = { + .name = "cg2900-uart", + .dev = { + .platform_data = &cg2900_uart_platform_data, + .parent = &ux500_cg2900_device.dev, + }, + .num_resources = ARRAY_SIZE(cg2900_uart_resources), + .resource = cg2900_uart_resources, +}; +#endif /* CONFIG_MFD_CG2900_UART */ + +void __init u5500_cg2900_init(void) +{ +#ifdef CONFIG_MFD_CG2900_TEST + dcg2900_init_platdata(&cg2900_test_platform_data); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_UART + dcg2900_init_platdata(&cg2900_uart_platform_data); +#endif /* CONFIG_MFD_CG2900_UART */ + + platform_device_register(&ux500_cg2900_device); +#ifdef CONFIG_MFD_CG2900_UART + platform_device_register(&ux500_cg2900_uart_device); +#endif /* CONFIG_MFD_CG2900_UART */ +#ifdef CONFIG_MFD_CG2900_TEST + platform_device_register(&ux500_cg2900_test_device); +#endif /* CONFIG_MFD_CG2900_TEST */ +#ifdef CONFIG_MFD_CG2900_CHIP + platform_device_register(&ux500_cg2900_chip_device); +#endif /* CONFIG_MFD_CG2900_CHIP */ +} diff --git a/arch/arm/mach-ux500/board-u5500-mcde.c b/arch/arm/mach-ux500/board-u5500-mcde.c new file mode 100644 index 00000000000..cf7d98ed6ed --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-mcde.c @@ -0,0 +1,493 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/dispdev.h> +#include <video/av8100.h> +#include <video/mcde_display.h> +#include <video/mcde_display-generic_dsi.h> +#include <video/mcde_display-av8100.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> + +#define DSI_UNIT_INTERVAL_0 0xA +#define DSI_UNIT_INTERVAL_2 0x5 + +#define PRIMARY_DISPLAY_ID 0 +#define TERTIARY_DISPLAY_ID 1 + +#ifdef CONFIG_FB_MCDE + +/* The initialization of hdmi disp driver must be delayed in order to + * ensure that inputclk will be available (needed by hdmi hw) */ +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +static struct delayed_work work_dispreg_hdmi; +#define DISPREG_HDMI_DELAY 6000 +#endif + +#define MCDE_NR_OF_DISPLAYS 2 +static int display_initialized_during_boot; + +static int __init startup_graphics_setup(char *str) +{ + + if (get_option(&str, &display_initialized_during_boot) != 1) + display_initialized_during_boot = 0; + + switch (display_initialized_during_boot) { + case 1: + pr_info("Startup graphics support\n"); + break; + case 0: + default: + pr_info("No startup graphics supported\n"); + break; + }; + + return 1; +} +__setup("startup_graphics=", startup_graphics_setup); + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY +static struct mcde_port port0 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = DSI_VIDEO_MODE, + .link = 0, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, +#else + .sync_src = MCDE_SYNCSRC_BTA, + .update_auto_trig = false, +#endif + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_0, + .clk_cont = false, + .data_lanes_swap = false, + }, + }, +}; + +struct mcde_display_generic_platform_data generic_display0_pdata = { + .reset_gpio = 226, + .reset_delay = 10, + .sleep_out_delay = 140, +#ifdef CONFIG_REGULATOR + .regulator_id = "v-display", + .min_supply_voltage = 2500000, /* 2.5V */ + .max_supply_voltage = 2700000 /* 2.7V */ +#endif +}; + +struct mcde_display_device generic_display0 = { + .name = "mcde_disp_generic", + .id = PRIMARY_DISPLAY_ID, + .port = &port0, + .chnl_id = MCDE_CHNL_A, + .fifo = MCDE_FIFO_A, +#ifdef CONFIG_MCDE_DISPLAY_PRIMARY_16BPP + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, +#else + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, +#endif + .native_x_res = 864, + .native_y_res = 480, +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC + .synchronized_update = true, +#else + .synchronized_update = false, +#endif + /* TODO: Remove rotation buffers once ESRAM driver is completed */ + .rotbuf1 = U5500_ESRAM_BASE + 0x20000 * 2, + .rotbuf2 = U5500_ESRAM_BASE + 0x20000 * 2 + 0x10000, + .dev = { + .platform_data = &generic_display0_pdata, + }, +}; +#endif /* CONFIG_DISPLAY_GENERIC_DSI_PRIMARY */ + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY +static struct mcde_port port2 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = DSI_VIDEO_MODE, + .link = 1, +#ifdef CONFIG_AV8100_HWTRIG_INT + .sync_src = MCDE_SYNCSRC_TE0, +#endif +#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3 + .sync_src = MCDE_SYNCSRC_TE1, +#endif +#ifdef CONFIG_AV8100_HWTRIG_DSI_TE + .sync_src = MCDE_SYNCSRC_TE_POLLING, +#endif +#ifdef CONFIG_AV8100_HWTRIG_NONE + .sync_src = MCDE_SYNCSRC_OFF, +#endif + .update_auto_trig = true, + .phy = { + .dsi = { + .virt_id = 0, + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_2, + .clk_cont = false, + .data_lanes_swap = false, + }, + }, + .hdmi_sdtv_switch = HDMI_SWITCH, +}; + +struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = { + .reset_gpio = 0, + .reset_delay = 1, + .regulator_id = NULL, + .cvbs_regulator_id = "v-av8100-AV-switch", + .ddb_id = 1, + .rgb_2_yCbCr_transform = { + .matrix = { + {0x42, 0x81, 0x19}, + {0xffda, 0xffb6, 0x70}, + {0x70, 0xffa2, 0xffee}, + }, + .offset = {0x80, 0x10, 0x80}, + } +}; + +struct mcde_display_device av8100_hdmi = { + .name = "av8100_hdmi", + .id = TERTIARY_DISPLAY_ID, + .port = &port2, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 1280, + .native_y_res = 720, + .synchronized_update = false, + .dev = { + .platform_data = &av8100_hdmi_pdata, + }, + .platform_enable = NULL, + .platform_disable = NULL, +}; + +static void delayed_work_dispreg_hdmi(struct work_struct *ptr) +{ + if (mcde_display_device_register(&av8100_hdmi)) + pr_warning("Failed to register av8100_hdmi\n"); +} +#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */ + +/* +* This function will create the framebuffer for the display that is registered. +*/ +static int display_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = dev; + u16 width, height; + u16 virtual_width, virtual_height; + u32 rotate = FB_ROTATE_UR; + struct fb_info *fbi; + + if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) + return 0; + + if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= MCDE_NR_OF_DISPLAYS) + return 0; + + mcde_dss_get_native_resolution(ddev, &width, &height); + +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY + if (ddev->id == PRIMARY_DISPLAY_ID) { + switch (CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE) { + case 0: + rotate = FB_ROTATE_UR; + break; + case 90: + rotate = FB_ROTATE_CW; + swap(width, height); + break; + case 180: + rotate = FB_ROTATE_UD; + break; + case 270: + rotate = FB_ROTATE_CCW; + swap(width, height); + break; + } + } +#endif + + virtual_width = width; + virtual_height = height * 2; +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC + if (ddev->id == PRIMARY_DISPLAY_ID) + virtual_height = height; +#endif + + if (ddev->id == TERTIARY_DISPLAY_ID) { +#ifdef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + hdmi_fb_onoff(ddev, 1, 0, 0); +#endif /* CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE */ + } else { + /* Create frame buffer */ + fbi = mcde_fb_create(ddev, + width, height, + virtual_width, virtual_height, + ddev->default_pixel_format, + rotate); + + if (IS_ERR(fbi)) + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", + ddev->name); + else + dev_info(&ddev->dev, "Framebuffer created (%s)\n", + ddev->name); + +#ifdef CONFIG_DISPDEV + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true) < 0) + dev_warn(&ddev->dev, + "Failed to create disp for display %s\n", + ddev->name); + else + dev_info(&ddev->dev, "Disp dev created for (%s)\n", + ddev->name); +#endif + } + + return 0; +} + +static struct notifier_block display_nb = { + .notifier_call = display_postregistered_callback, +}; + +/* +* This function is used to refresh the display (lcd, hdmi, tvout) with black +* when the framebuffer is registered. +* The main display will not be updated if startup graphics is displayed +* from u-boot. +*/ +#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + int i; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + var = info->var; + fix = info->fix; + + /* Apply overlay info */ + for (i = 0; i < mfb->num_ovlys; i++) { + struct mcde_overlay *ovly = mfb->ovlys[i]; + struct mcde_overlay_info ovly_info; + struct mcde_fb *mfb = to_mcde_fb(info); + memset(&ovly_info, 0, sizeof(ovly_info)); + ovly_info.paddr = fix.smem_start + + fix.line_length * var.yoffset; + if (ovly_info.paddr + fix.line_length * var.yres + > fix.smem_start + fix.smem_len) + ovly_info.paddr = fix.smem_start; + ovly_info.fmt = mfb->pix_fmt; + ovly_info.stride = fix.line_length; + ovly_info.w = var.xres; + ovly_info.h = var.yres; + ovly_info.dirty.w = var.xres; + ovly_info.dirty.h = var.yres; + (void) mcde_dss_apply_overlay(ovly, &ovly_info); + ret = mcde_dss_update_overlay(ovly); + if (ret) + break; + } + + return ret; +} +#else +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + if (mfb->id == 0 && display_initialized_during_boot) + goto out; + + var = info->var; + fix = info->fix; + var.yoffset = var.yoffset ? 0 : var.yres; + if (info->fbops->fb_pan_display) + ret = info->fbops->fb_pan_display(&var, info); +out: + return ret; +} +#endif + + +static struct notifier_block framebuffer_nb = { + .notifier_call = framebuffer_postregistered_callback, +}; + +int __init init_display_devices(void) +{ + int ret; + + ret = fb_register_client(&framebuffer_nb); + if (ret) + pr_warning("Failed to register framebuffer notifier\n"); + + ret = mcde_dss_register_notifier(&display_nb); + if (ret) + pr_warning("Failed to register dss notifier\n"); + +#ifdef CONFIG_DISPLAY_GENERIC_PRIMARY + if (display_initialized_during_boot) + generic_display0.power_mode = MCDE_DISPLAY_PM_STANDBY; + ret = mcde_display_device_register(&generic_display0); + if (ret) + pr_warning("Failed to register generic display device 0\n"); +#endif + +#ifdef CONFIG_DISPLAY_AV8100_TERTIARY + INIT_DELAYED_WORK_DEFERRABLE(&work_dispreg_hdmi, + delayed_work_dispreg_hdmi); + + schedule_delayed_work(&work_dispreg_hdmi, + msecs_to_jiffies(DISPREG_HDMI_DELAY)); +#endif + + return ret; +} + +struct mcde_display_device *mcde_get_main_display(void) +{ +#if defined(CONFIG_DISPLAY_GENERIC_DSI_PRIMARY) + return &generic_display0; +#elif defined(CONFIG_DISPLAY_AV8100_TERTIARY) + return &av8100_hdmi; +#else + return NULL; +#endif +} +EXPORT_SYMBOL(mcde_get_main_display); + +void hdmi_fb_onoff(struct mcde_display_device *ddev, + bool enable, u8 cea, u8 vesa_cea_nr) +{ + struct fb_info *fbi; + u16 w, h; + u16 vw, vh; + u32 rotate = FB_ROTATE_UR; + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(&ddev->dev, "%s\n", __func__); + dev_dbg(&ddev->dev, "en:%d cea:%d nr:%d\n", enable, cea, vesa_cea_nr); + + if (enable) { + if (ddev->enabled) { + dev_dbg(&ddev->dev, "Display is already enabled.\n"); + return; + } + + /* Create fb */ + if (ddev->fbi == NULL) { + /* Note: change when dynamic buffering is available */ + int buffering = 2; + + /* Get default values */ + mcde_dss_get_native_resolution(ddev, &w, &h); + vw = w; + vh = h * buffering; + + if (vesa_cea_nr != 0) + ddev->ceanr_convert(ddev, cea, vesa_cea_nr, + buffering, &w, &h, &vw, &vh); + + fbi = mcde_fb_create(ddev, w, h, vw, vh, + ddev->default_pixel_format, rotate); + + if (IS_ERR(fbi)) { + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", + ddev->name); + goto hdmi_fb_onoff_end; + } else { + dev_info(&ddev->dev, + "Framebuffer created (%s)\n", + ddev->name); + } + driver_data->fbdevname = (char *)dev_name(fbi->dev); + +#ifdef CONFIG_DISPDEV + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true) < 0) + dev_warn(&ddev->dev, + "Failed to create disp for %s\n", + ddev->name); + else + dev_info(&ddev->dev, + "Disp dev created for (%s)\n", + ddev->name); +#endif /* CONFIG_DISPDEV */ + } + } else { + if (!ddev->enabled) { + dev_dbg(&ddev->dev, "Display %s is already disabled.\n", + ddev->name); + return; + } + +#ifdef CONFIG_DISPDEV + dispdev_destroy(ddev); +#endif /* CONFIG_DISPDEV */ + mcde_fb_destroy(ddev); + } + +hdmi_fb_onoff_end: + return; +} +EXPORT_SYMBOL(hdmi_fb_onoff); + +module_init(init_display_devices); +#endif diff --git a/arch/arm/mach-ux500/board-u5500-pins.c b/arch/arm/mach-ux500/board-u5500-pins.c new file mode 100644 index 00000000000..ddbe827ca83 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-pins.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <plat/pincfg.h> +#include <plat/gpio.h> + +#include "pins-db5500.h" +#include "pins.h" + +static pin_cfg_t u5500_pins_default[] = { + /* Keypad */ + GPIO128_KP_I0 | PIN_INPUT_PULLUP, + GPIO130_KP_I1 | PIN_INPUT_PULLUP, + GPIO132_KP_I2 | PIN_INPUT_PULLUP, + GPIO134_KP_I3 | PIN_INPUT_PULLUP, + GPIO137_KP_O4 | PIN_INPUT_PULLUP, + GPIO139_KP_O5 | PIN_INPUT_PULLUP, + + /* MSP */ + GPIO32_MSP0_TCK | PIN_INPUT_PULLDOWN, + GPIO33_MSP0_TFS | PIN_INPUT_PULLDOWN, + GPIO34_MSP0_TXD | PIN_INPUT_PULLDOWN, + GPIO35_MSP0_RXD | PIN_INPUT_PULLDOWN, + GPIO96_MSP1_TCK | PIN_INPUT_PULLDOWN, + GPIO97_MSP1_TFS | PIN_INPUT_PULLDOWN, + GPIO98_MSP1_TXD | PIN_INPUT_PULLDOWN, + GPIO99_MSP1_RXD | PIN_INPUT_PULLDOWN, + GPIO220_MSP2_TCK | PIN_OUTPUT_LOW, + GPIO221_MSP2_TFS | PIN_OUTPUT_LOW, + GPIO222_MSP2_TXD | PIN_OUTPUT_LOW, + + /* DISPLAY_ENABLE */ + GPIO226_GPIO | PIN_OUTPUT_LOW, + + /* Backlight Enable */ + GPIO224_GPIO | PIN_OUTPUT_HIGH, + + /* MMC0 (POP eMMC) */ + GPIO5_MC0_DAT0 | PIN_INPUT_PULLUP, + GPIO6_MC0_DAT1 | PIN_INPUT_PULLUP, + GPIO7_MC0_DAT2 | PIN_INPUT_PULLUP, + GPIO8_MC0_DAT3 | PIN_INPUT_PULLUP, + GPIO9_MC0_DAT4 | PIN_INPUT_PULLUP, + GPIO10_MC0_DAT5 | PIN_INPUT_PULLUP, + GPIO11_MC0_DAT6 | PIN_INPUT_PULLUP, + GPIO12_MC0_DAT7 | PIN_INPUT_PULLUP, + GPIO13_MC0_CMD | PIN_INPUT_PULLUP, + GPIO14_MC0_CLK | PIN_OUTPUT_LOW, + + /* UART3 */ + GPIO165_U3_RXD | PIN_INPUT_PULLUP, + GPIO166_U3_TXD | PIN_OUTPUT_HIGH, + GPIO167_U3_RTSn | PIN_OUTPUT_HIGH, + GPIO168_U3_CTSn | PIN_INPUT_PULLUP, + + /* AB5500 */ + GPIO78_IRQn, + + /* TOUCH_IRQ */ + GPIO179_GPIO | PIN_INPUT_PULLUP, + + /* SDI1 (SD-CARD) */ + GPIO191_MC1_DAT0 | PIN_INPUT_PULLUP, + GPIO192_MC1_DAT1 | PIN_INPUT_PULLUP, + GPIO193_MC1_DAT2 | PIN_INPUT_PULLUP, + GPIO194_MC1_DAT3 | PIN_INPUT_PULLUP, + GPIO195_MC1_CLK | PIN_OUTPUT_LOW, + GPIO196_MC1_CMD | PIN_INPUT_PULLUP, + GPIO197_MC1_CMDDIR | PIN_OUTPUT_HIGH, + GPIO198_MC1_FBCLK | PIN_INPUT_NOPULL, + GPIO199_MC1_DAT0DIR | PIN_OUTPUT_HIGH, + /* SD-CARD detect/levelshifter pins */ + GPIO180_GPIO | PIN_INPUT_PULLUP, + GPIO227_GPIO, + GPIO185_GPIO, + + /* SDI3 (SDIO) */ + GPIO171_MC3_DAT0 | PIN_INPUT_PULLUP, + GPIO172_MC3_DAT1 | PIN_INPUT_PULLUP, + GPIO173_MC3_DAT2 | PIN_INPUT_PULLUP, + GPIO174_MC3_DAT3 | PIN_INPUT_PULLUP, + GPIO175_MC3_CMD | PIN_INPUT_PULLUP, + GPIO176_MC3_CLK | PIN_OUTPUT_LOW, + + /* Display & HDMI HW sync */ + GPIO204_LCD_VSI1 | PIN_INPUT_PULLUP, +}; + +static UX500_PINS(u5500_pins_i2c1, + GPIO3_I2C1_SCL, + GPIO4_I2C1_SDA, +); + +static UX500_PINS(u5500_pins_i2c2, + GPIO218_I2C2_SCL, + GPIO219_I2C2_SDA, +); + +static struct ux500_pin_lookup u5500_pins[] = { + PIN_LOOKUP("nmk-i2c.1", &u5500_pins_i2c1), + PIN_LOOKUP("nmk-i2c.2", &u5500_pins_i2c2), +}; + +void __init u5500_pins_init(void) +{ + nmk_config_pins(u5500_pins_default, ARRAY_SIZE(u5500_pins_default)); + ux500_pins_add(u5500_pins, ARRAY_SIZE(u5500_pins)); +} diff --git a/arch/arm/mach-ux500/board-u5500-regulators.c b/arch/arm/mach-ux500/board-u5500-regulators.c new file mode 100644 index 00000000000..f2b17974227 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-regulators.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/ab5500.h> + +#include "regulator-u5500.h" +#include "board-u5500.h" + +/* + * AB5500 + */ + +static struct regulator_consumer_supply ab5500_ldo_d_consumers[] = { +}; + +static struct regulator_consumer_supply ab5500_ldo_g_consumers[] = { + REGULATOR_SUPPLY("v-MMC-SD", "sdi1"), +}; + +static struct regulator_consumer_supply ab5500_ldo_h_consumers[] = { + REGULATOR_SUPPLY("v-display", NULL), + REGULATOR_SUPPLY("vdd", "1-004b"), /* Synaptics */ + REGULATOR_SUPPLY("vin", "2-0036"), /* LM3530 */ +}; + +static struct regulator_consumer_supply ab5500_ldo_k_consumers[] = { + REGULATOR_SUPPLY("v-accel", "lsm303dlh.0"), + REGULATOR_SUPPLY("v-mag", "lsm303dlh.1"), + REGULATOR_SUPPLY("v-mmio-camera", "mmio_camera"), +}; + +static struct regulator_consumer_supply ab5500_ldo_l_consumers[] = { +}; + +static struct regulator_consumer_supply ab5500_ldo_s_consumers[] = { + REGULATOR_SUPPLY("v-ana", "mcde"), + REGULATOR_SUPPLY("v-ana", "mmio_camera"), +}; + +static struct regulator_consumer_supply ab5500_ldo_vdigmic_consumers[] = { +}; + +static struct regulator_consumer_supply ab5500_ldo_sim_consumers[] = { +}; + +static struct regulator_init_data +ab5500_regulator_init_data[AB5500_NUM_REGULATORS] = { + /* AB internal analog */ + [AB5500_LDO_D] = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_d_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_d_consumers), + }, + /* SD Card */ + [AB5500_LDO_G] = { + .constraints = { + .min_uV = 1200000, + .max_uV = 2910000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_g_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_g_consumers), + }, + /* Display */ + [AB5500_LDO_H] = { + .constraints = { + .min_uV = 2790000, + .max_uV = 2790000, + .apply_uV = 1, + .boot_on = 1, /* display on during boot */ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_h_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_h_consumers), + }, + /* Camera */ + [AB5500_LDO_K] = { + .constraints = { + .min_uV = 2790000, + .max_uV = 2790000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_k_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_k_consumers), + }, + /* External eMMC */ + [AB5500_LDO_L] = { + .constraints = { + .min_uV = 1200000, + .max_uV = 2910000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_l_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_l_consumers), + }, + [AB5500_LDO_S] = { + .constraints = { + .name = "VANA", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_s_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_s_consumers), + }, + [AB5500_LDO_VDIGMIC] = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_vdigmic_consumers, + .num_consumer_supplies = + ARRAY_SIZE(ab5500_ldo_vdigmic_consumers), + }, + [AB5500_LDO_SIM] = { + .constraints = { + .min_uV = 1875000, + .max_uV = 2900000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = ab5500_ldo_sim_consumers, + .num_consumer_supplies = ARRAY_SIZE(ab5500_ldo_sim_consumers), + }, +}; + +struct ab5500_regulator_platform_data u5500_ab5500_regulator_data = { + .regulator = ab5500_regulator_init_data, + .num_regulator = ARRAY_SIZE(ab5500_regulator_init_data), +}; + +/* + * Power state, ePOD, etc. + */ + +static struct regulator_consumer_supply u5500_vape_consumers[] = { + REGULATOR_SUPPLY("v-ape", NULL), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"), + REGULATOR_SUPPLY("v-mmc", "sdi0"), + REGULATOR_SUPPLY("v-mmc", "sdi1"), + REGULATOR_SUPPLY("v-mmc", "sdi2"), + REGULATOR_SUPPLY("v-mmc", "sdi3"), + REGULATOR_SUPPLY("v-mmc", "sdi4"), + REGULATOR_SUPPLY("v-uart", "uart0"), + REGULATOR_SUPPLY("v-uart", "uart1"), + REGULATOR_SUPPLY("v-uart", "uart2"), + REGULATOR_SUPPLY("v-uart", "uart3"), +}; + +static struct regulator_init_data * +u5500_regulator_init_data[U5500_NUM_REGULATORS] __initdata = { + [U5500_REGULATOR_VAPE] = (struct regulator_init_data []) { + { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = u5500_vape_consumers, + .num_consumer_supplies = ARRAY_SIZE(u5500_vape_consumers), + } + }, +}; + +void __init u5500_regulators_init(void) +{ + platform_device_register_data(NULL, "u5500-regulators", -1, + u5500_regulator_init_data, + sizeof(u5500_regulator_init_data)); +} diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c new file mode 100644 index 00000000000..f42c5b4e4b3 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-sdi.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2010 ST-Ericsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/amba/mmci.h> +#include <linux/mmc/host.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <plat/ste_dma40.h> +#include <plat/pincfg.h> +#include <mach/devices.h> +#include <mach/gpio.h> +#include <mach/ste-dma40-db5500.h> + +#include "pins-db5500.h" +#include "devices-db5500.h" +#include "board-u5500.h" + +/* + * SDI0 (EMMC) + */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg sdi0_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi0_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV24_SDMMC0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +/* + * SDI1 (SD/MMC) + */ + +static struct stedma40_chan_cfg sdi1_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV25_SDMMC1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi1_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV25_SDMMC1_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +/* + * SDI3 (SDIO) + */ +static struct stedma40_chan_cfg sdi3_dma_cfg_rx = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV27_SDMMC3_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi3_dma_cfg_tx = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV27_SDMMC3_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +#endif + +static struct mmci_platform_data u5500_sdi0_data = { + .vcc = "v-mmc", + .ocr_mask = MMC_VDD_165_195, + .f_max = 50000000, + .disable = 500, + .pm_flags = MMC_PM_KEEP_POWER, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_DISABLE, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi0_dma_cfg_rx, + .dma_tx_param = &sdi0_dma_cfg_tx, +#endif +}; + +static void u5500_sdi1_vdd_handler(struct device *dev, unsigned int vdd, + unsigned char power_mode) +{ + switch (power_mode) { + case MMC_POWER_UP: + case MMC_POWER_ON: + /* + * Level shifter voltage should depend on vdd to when deciding + * on either 1.8V or 2.9V. Once the decision has been made the + * level shifter must be disabled and re-enabled with a changed + * select signal in order to switch the voltage. Since there is + * no framework support yet for indicating 1.8V in vdd, use the + * default 2.9V. + */ + + /* Enable level shifter */ + gpio_direction_output(GPIO_MMC_CARD_CTRL, 1); + udelay(100); + break; + case MMC_POWER_OFF: + /* Disable level shifter */ + gpio_direction_output(GPIO_MMC_CARD_CTRL, 0); + break; + } +} + +static struct mmci_platform_data u5500_sdi1_data = { + .vcc = "v-mmc", + .vcard = "v-MMC-SD", + .vdd_handler = u5500_sdi1_vdd_handler, + .ocr_mask = MMC_VDD_29_30, + .disable = 500, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_DISABLE, + .gpio_cd = GPIO_SDMMC_CD, + .gpio_wp = -1, + .cd_invert = true, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi1_dma_cfg_rx, + .dma_tx_param = &sdi1_dma_cfg_tx, +#endif +}; +static void sdi1_configure(void) +{ + int pin[2]; + int ret; + + /* Level-shifter GPIOs */ + pin[0] = GPIO_MMC_CARD_CTRL; + pin[1] = GPIO_MMC_CARD_VSEL; + + ret = gpio_request(pin[0], "MMC_CARD_CTRL"); + if (!ret) + ret = gpio_request(pin[1], "MMC_CARD_VSEL"); + + if (ret) { + pr_err("mach-u5500: error in configuring \ + GPIO pins for MMC\n"); + return; + } + /* Select the default 2.9V and eanble level shifter */ + gpio_direction_output(pin[0], 1); + gpio_direction_output(pin[1], 1); + +} + +/* + * SDI3 (SDIO WLAN) + */ +static irqreturn_t sdio_irq(int irq, void *dev_id) +{ + struct mmc_host *host = dev_id; + + /* + * Signal an sdio irq for the sdio client. + * If we are in suspend state the host has been claimed + * by the pm framework, which prevents any sdio request + * to be served until the host gets resumed and released. + */ + mmc_signal_sdio_irq(host); + + return IRQ_HANDLED; +} + +static void sdio_config_irq(struct mmc_host *host, + bool cfg_as_dat1, + int irq_pin, + pin_cfg_t irq_dat1, + pin_cfg_t irq_gpio) +{ + /* + * If the pin mux switch or interrupt registration fails we're in deep + * trouble and there is no decent recovery. + */ + if (!gpio_is_valid(irq_pin)) { + dev_err(mmc_dev(host), + "invalid irq pin (%d) for sdio irq\n", irq_pin); + return; + } + + if (!cfg_as_dat1) { + + /* + * SDIO irq shall be handled as a gpio irq. We configure the + * dat[1] as gpio and register a gpio irq handler. + */ + + if (nmk_config_pin(irq_gpio, 0)) + dev_err(mmc_dev(host), + "err config irq gpio (%lu) for sdio irq\n", + irq_gpio); + + /* We use threaded irq */ + if (request_threaded_irq(gpio_to_irq(irq_pin), + NULL, + sdio_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + dev_driver_string(mmc_dev(host)), + host)) + dev_err(mmc_dev(host), + "err request_threaded_irq for sdio irq\n"); + + /* + * Set the irq as a wakeup irq to be able to be woken up + * from the suspend state and thus trigger a resume of + * the system. + */ + if (enable_irq_wake(gpio_to_irq(irq_pin))) + dev_err(mmc_dev(host), + "err enabling wakeup irq for sdio irq\n"); + + /* + * Workaround to fix PL180 hw-problem of missing sdio irqs. + * If the DAT1 line has been asserted low we signal an sdio + * irq. + */ + if (gpio_request(irq_pin, dev_driver_string(mmc_dev(host)))) + dev_err(mmc_dev(host), + "err requesting irq for sdio irq\n"); + + if (!gpio_get_value(irq_pin)) + mmc_signal_sdio_irq(host); + + gpio_free(irq_pin); + + } else { + + /* + * SDIO irq shall be handled as dat[1] irq by the mmci + * driver. Configure the gpio back into dat[1] and remove + * the gpio irq handler. + */ + if (disable_irq_wake(gpio_to_irq(irq_pin))) + dev_err(mmc_dev(host), + "err disabling wakeup irq for sdio irq\n"); + + free_irq(gpio_to_irq(irq_pin), host); + + if (nmk_config_pin(irq_dat1, 0)) + dev_err(mmc_dev(host), + "err config irq dat1 (%lu) for sdio irq\n", + irq_dat1); + + } +} + +static void wakeup_handler_sdi3(struct mmc_host *host, bool wakeup) +{ + if (host->card && mmc_card_sdio(host->card) && host->sdio_irqs) + sdio_config_irq(host, + wakeup, + 172, + GPIO172_MC3_DAT1 | PIN_INPUT_PULLUP, + GPIO172_GPIO | PIN_INPUT_PULLUP); +} + +static struct mmci_platform_data u5500_sdi3_data = { + .vcc = "v-mmc", + .disable = 50, + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_DISABLE | + MMC_CAP_SDIO_IRQ | + MMC_CAP_BROKEN_SDIO_CMD53, + .pm_flags = MMC_PM_KEEP_POWER, + .gpio_cd = -1, + .gpio_wp = -1, + .wakeup_handler = wakeup_handler_sdi3, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi3_dma_cfg_rx, + .dma_tx_param = &sdi3_dma_cfg_tx, +#endif +}; + +static int __init u5500_mmc_init(void) +{ + db5500_add_sdi0(&u5500_sdi0_data); + sdi1_configure(); + db5500_add_sdi1(&u5500_sdi1_data); + db5500_add_sdi3(&u5500_sdi3_data); + + return 0; +} + +fs_initcall(u5500_mmc_init); diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 4430e69cf53..951339b0df9 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -1,41 +1,398 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 */ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/amba/bus.h> +#include <linux/amba/mmci.h> +#include <linux/amba/pl022.h> #include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/i2s/i2s.h> +#include <linux/input/synaptics_i2c_rmi4.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/abx500/ab5500.h> +#include <linux/mfd/abx500.h> +#include <linux/led-lm3530.h> +#include <linux/lsm303dlh.h> +#include <linux/leds-ab5500.h> + +#include <video/av8100.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> -#include <mach/hardware.h> +#include <plat/pincfg.h> +#include <plat/i2c.h> + +#include <mach/ste-dma40-db5500.h> +#include <mach/msp.h> #include <mach/devices.h> #include <mach/setup.h> +#include <mach/db5500-keypad.h> + +#include "pins-db5500.h" +#include "devices-db5500.h" +#include "board-u5500.h" + +/* + * LSM303DLH + */ + +static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata = { + .name_a = "lsm303dlh.0", + .name_m = "lsm303dlh.1", + .axis_map_x = 1, + .axis_map_y = 0, + .axis_map_z = 2, + .negative_x = 1, + .negative_y = 1, + .negative_z = 1, +}; + +/* + * Touchscreen + */ + +static struct synaptics_rmi4_platform_data rmi4_i2c_platformdata = { + .irq_number = GPIO_TO_IRQ(179), + .irq_type = (IRQF_TRIGGER_FALLING | IRQF_SHARED), +#if CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATION_ANGLE == 270 + .x_flip = true, + .y_flip = false, +#else + .x_flip = false, + .y_flip = true, +#endif + .regulator_en = true, +}; + +static struct av8100_platform_data av8100_plat_data = { + .irq = GPIO_TO_IRQ(223), + .reset = 225, + .alt_powerupseq = true, + .mclk_freq = 1, /* MCLK_RNG_22_27 */ +}; + + +static struct lm3530_platform_data u5500_als_platform_data = { + .mode = LM3530_BL_MODE_MANUAL, + .als_input_mode = LM3530_INPUT_ALS1, + .max_current = LM3530_FS_CURR_26mA, + .pwm_pol_hi = true, + .als_avrg_time = LM3530_ALS_AVRG_TIME_512ms, + .brt_ramp_law = 1, /* Linear */ + .brt_ramp_fall = LM3530_RAMP_TIME_1ms, + .brt_ramp_rise = LM3530_RAMP_TIME_1ms, + .als1_resistor_sel = LM3530_ALS_IMPD_2_27kOhm, + .als2_resistor_sel = LM3530_ALS_IMPD_2_27kOhm, + .brt_val = 0x7F, /* Max brightness */ +}; + + +/* leds-ab5500 */ +static struct ab5500_hvleds_platform_data ab5500_hvleds_data = { + .hw_blink = false, + .leds = { + [0] = { + .name = "ab5500-hvled:channel-0:", + .led_id = 0, + .status = AB5500_LED_ON, + .max_current = 10, /* wrong value may damage h/w */ + }, + [1] = { + .name = "ab5500-hvled:channel-1:", + .led_id = 1, + .status = AB5500_LED_ON, + .max_current = 10, /* wrong value may damage h/w */ + }, + [2] { + .name = "ab5500-hvled:channel-2:", + .led_id = 2, + .status = AB5500_LED_ON, + .max_current = 10, /* wrong value may damage h/w */ + }, + }, +}; + +/* + * I2C + */ + +#define U5500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm) \ +static struct nmk_i2c_controller u5500_i2c##id##_data = { \ + /* \ + * slave data setup time, which is \ + * 250 ns,100ns,10ns which is 14,6,2 \ + * respectively for a 48 Mhz \ + * i2c clock \ + */ \ + .slsu = _slsu, \ + /* Tx FIFO threshold */ \ + .tft = _tft, \ + /* Rx FIFO threshold */ \ + .rft = _rft, \ + /* std. mode operation */ \ + .clk_freq = clk, \ + /* Slave response timeout(ms) */\ + .timeout = t_out, \ + .sm = _sm, \ +} + +/* + * The board uses 3 i2c controllers, initialize all of + * them with slave data setup time of 250 ns, + * Tx & Rx FIFO threshold values as 1 and standard + * mode of operation + */ + +U5500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, 200, I2C_FREQ_MODE_FAST); +U5500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, 200, I2C_FREQ_MODE_FAST); +U5500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, 200, I2C_FREQ_MODE_FAST); + +static struct i2c_board_info __initdata u5500_i2c1_devices[] = { + { + I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B), + .platform_data = &rmi4_i2c_platformdata, + }, +}; + +static struct i2c_board_info __initdata u5500_i2c2_devices[] = { + { + /* LSM303DLH Accelerometer */ + I2C_BOARD_INFO("lsm303dlh_a", 0x19), + .platform_data = &lsm303dlh_pdata, + }, + { + /* LSM303DLH Magnetometer */ + I2C_BOARD_INFO("lsm303dlh_m", 0x1E), + .platform_data = &lsm303dlh_pdata, + }, + { + /* Backlight */ + I2C_BOARD_INFO("lm3530-led", 0x36), + .platform_data = &u5500_als_platform_data, + }, + { + I2C_BOARD_INFO("av8100", 0x70), + .platform_data = &av8100_plat_data, + }, +}; + +/* + * Keypad + */ + +static const unsigned int u5500_keymap[] = { + KEY(4, 0, KEY_CAMERA), /* Camera2 */ + KEY(4, 1, KEY_CAMERA_FOCUS), /* Camera1 */ + KEY(4, 2, KEY_MENU), + KEY(4, 3, KEY_BACK), + KEY(5, 2, KEY_SEND), + KEY(5, 3, KEY_HOME), +#ifndef CONFIG_INPUT_AB8500_PONKEY + /* AB5500 ONSWa is also hooked up to this key */ + KEY(8, 0, KEY_END), +#endif + KEY(8, 1, KEY_VOLUMEUP), + KEY(8, 2, KEY_VOLUMEDOWN), +}; + +static struct matrix_keymap_data u5500_keymap_data = { + .keymap = u5500_keymap, + .keymap_size = ARRAY_SIZE(u5500_keymap), +}; + +static struct db5500_keypad_platform_data u5500_keypad_board = { + .keymap_data = &u5500_keymap_data, + .no_autorepeat = true, + .debounce_ms = 40, /* milliseconds */ +}; + + +/* + * MSP + */ + +#define MSP_DMA(num, eventline) \ +static struct stedma40_chan_cfg msp##num##_dma_rx = { \ + .high_priority = true, \ + .dir = STEDMA40_PERIPH_TO_MEM, \ + .src_dev_type = eventline##_RX, \ + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, \ + .src_info.psize = STEDMA40_PSIZE_LOG_4, \ + .dst_info.psize = STEDMA40_PSIZE_LOG_4, \ +}; \ + \ +static struct stedma40_chan_cfg msp##num##_dma_tx = { \ + .high_priority = true, \ + .dir = STEDMA40_MEM_TO_PERIPH, \ + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, \ + .dst_dev_type = eventline##_TX, \ + .src_info.psize = STEDMA40_PSIZE_LOG_4, \ + .dst_info.psize = STEDMA40_PSIZE_LOG_4, \ +} + +MSP_DMA(0, DB5500_DMA_DEV9_MSP0); +MSP_DMA(1, DB5500_DMA_DEV10_MSP1); +MSP_DMA(2, DB5500_DMA_DEV11_MSP2); + +static struct msp_i2s_platform_data u5500_msp0_data = { + .id = MSP_0_CONTROLLER, + .msp_i2s_dma_rx = &msp0_dma_rx, + .msp_i2s_dma_tx = &msp0_dma_tx, +}; + +static struct msp_i2s_platform_data u5500_msp1_data = { + .id = MSP_1_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp1_dma_rx, + .msp_i2s_dma_tx = &msp1_dma_tx, +}; + +static struct msp_i2s_platform_data u5500_msp2_data = { + .id = MSP_2_I2S_CONTROLLER, + .msp_i2s_dma_rx = &msp2_dma_rx, + .msp_i2s_dma_tx = &msp2_dma_tx, +}; + +static struct i2s_board_info stm_i2s_board_info[] __initdata = { + { + .modalias = "i2s_device.0", + .id = 0, + .chip_select = 0, + }, + { + .modalias = "i2s_device.1", + .id = 1, + .chip_select = 1, + }, + { + .modalias = "i2s_device.2", + .id = 2, + .chip_select = 2, + }, +}; + +static void __init u5500_msp_init(void) +{ + db5500_add_msp0_i2s(&u5500_msp0_data); + db5500_add_msp1_i2s(&u5500_msp1_data); + db5500_add_msp2_i2s(&u5500_msp2_data); + + i2s_register_board_info(ARRAY_AND_SIZE(stm_i2s_board_info)); +} + +/* + * SPI + */ + +static struct pl022_ssp_controller u5500_spi1_data = { + .bus_id = 1, + .num_chipselect = 4, /* 3 possible CS lines + 1 for tests */ +}; + +static void __init u5500_spi_init(void) +{ + db5500_add_spi1(&u5500_spi1_data); +} + +static struct resource ab5500_resources[] = { + [0] = { + /*TODO Change this when prcmu driver arrives */ + .start = IRQ_DB5500_AB5500, + .end = IRQ_DB5500_AB5500, + .flags = IORESOURCE_IRQ + } +}; + +static struct ab5500_platform_data ab5500_plf_data = { + .irq = { + .base = IRQ_AB5500_BASE, + .count = AB5500_NR_IRQS, + }, + .pm_power_off = true, + .regulator = &u5500_ab5500_regulator_data, + .dev_data[AB5500_DEVID_LEDS] = &ab5500_hvleds_data, + .dev_data_sz[AB5500_DEVID_LEDS] = sizeof(ab5500_hvleds_data), +}; + +static struct platform_device u5500_ab5500_device = { + .name = "ab5500-core", + .id = 0, + .dev = { + .platform_data = &ab5500_plf_data, + }, + .num_resources = 1, + .resource = ab5500_resources, +}; -static struct amba_device *amba_board_devs[] __initdata = { - &ux500_uart0_device, - &ux500_uart1_device, - &ux500_uart2_device, +static struct platform_device *u5500_platform_devices[] __initdata = { + &u5500_ab5500_device, + &ux500_mcde_device, + &ux500_hwmem_device, + &ux500_b2r2_device, +#ifdef CONFIG_STM_TRACE + &ux500_stm_device, +#endif }; +static void __init u5500_i2c_init(void) +{ + db5500_add_i2c1(&u5500_i2c1_data); + db5500_add_i2c2(&u5500_i2c2_data); + db5500_add_i2c3(&u5500_i2c3_data); + + i2c_register_board_info(1, ARRAY_AND_SIZE(u5500_i2c1_devices)); + i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices)); +} + +static void __init u5500_uart_init(void) +{ + db5500_add_uart0(); + db5500_add_uart1(); + db5500_add_uart2(); + db5500_add_uart3(); +} + static void __init u5500_init_machine(void) { + u5500_regulators_init(); u5500_init_devices(); + u5500_pins_init(); + + u5500_cg2900_init(); - amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs)); + u5500_i2c_init(); + u5500_msp_init(); + u5500_spi_init(); + u5500_uart_init(); + + db5500_add_keypad(&u5500_keypad_board); + + platform_add_devices(u5500_platform_devices, + ARRAY_SIZE(u5500_platform_devices)); } -MACHINE_START(U8500, "ST-Ericsson U5500 Platform") - .phys_io = UX500_UART0_BASE, - .io_pg_offst = (IO_ADDRESS(UX500_UART0_BASE) >> 18) & 0xfffc, +MACHINE_START(U5500, "ST-Ericsson U5500 Platform") + .phys_io = U5500_UART0_BASE, + .io_pg_offst = (IO_ADDRESS(U5500_UART0_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .map_io = u5500_map_io, + .init_irq = ux500_init_irq, + .timer = &u8500_timer, + .init_machine = u5500_init_machine, +MACHINE_END + +MACHINE_START(B5500, "ST-Ericsson U5500 Big Board") + .phys_io = U5500_UART0_BASE, + .io_pg_offst = (IO_ADDRESS(U5500_UART0_BASE) >> 18) & 0xfffc, .boot_params = 0x00000100, .map_io = u5500_map_io, .init_irq = ux500_init_irq, - .timer = &ux500_timer, + .timer = &u8500_timer, .init_machine = u5500_init_machine, MACHINE_END diff --git a/arch/arm/mach-ux500/board-u5500.h b/arch/arm/mach-ux500/board-u5500.h new file mode 100644 index 00000000000..4a0dc94a1c3 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __BOARD_U5500_H +#define __BOARD_U5500_H + +#define GPIO_SDMMC_CD 180 +#define GPIO_MMC_CARD_CTRL 227 +#define GPIO_MMC_CARD_VSEL 185 + +struct ab5500_regulator_platform_data; +extern struct ab5500_regulator_platform_data u5500_ab5500_regulator_data; + +extern void u5500_pins_init(void); +extern void __init u5500_regulators_init(void); + +#ifdef CONFIG_MFD_CG2900 +extern void u5500_cg2900_init(void); +#else +static inline void u5500_cg2900_init(void) +{ + return; +}; +#endif + +#endif diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c new file mode 100644 index 00000000000..7a50007ddad --- /dev/null +++ b/arch/arm/mach-ux500/clock-db5500.c @@ -0,0 +1,793 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * Copyright (C) 2009 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/mfd/ab8500/sysctrl.h> +#include <linux/workqueue.h> +#include <linux/regulator/consumer.h> + +#include <plat/pincfg.h> + +#include <mach/hardware.h> +#include <mach/prcmu-fw-api.h> + +#include "clock.h" +#include "pins-db8500.h" +#include "prcmu-db5500.h" + +static DEFINE_MUTEX(sysclk_mutex); +static DEFINE_MUTEX(ab_ulpclk_mutex); +static DEFINE_MUTEX(audioclk_mutex); + +/* PLL operations. */ + +static int clk_pllsrc_enable(struct clk *clk) +{ + /* To enable pll */ + return 0; +} + +static void clk_pllsrc_disable(struct clk *clk) +{ + /* To disable pll */ +} + +static struct clkops pll_clk_ops = { + .enable = clk_pllsrc_enable, + .disable = clk_pllsrc_disable, +}; + +/* SysClk operations. */ + +static int request_sysclk(bool enable) +{ + static int requests; + + if ((enable && (requests++ == 0)) || (!enable && (--requests == 0))) + return db5500_prcmu_request_clock(DB5500_PRCMU_SYSCLK, enable); + return 0; +} + +static int sysclk_enable(struct clk *clk) +{ + static bool swat_enable; + int r; + + if (!swat_enable) { + r = ab8500_sysctrl_set(AB8500_SWATCTRL, + AB8500_SWATCTRL_SWATENABLE); + if (r) + return r; + + swat_enable = true; + } + + r = request_sysclk(true); + if (r) + return r; + + if (clk->cg_sel) { + r = ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, (u8)clk->cg_sel); + if (r) + (void)request_sysclk(false); + } + return r; +} + +static void sysclk_disable(struct clk *clk) +{ + int r; + + if (clk->cg_sel) { + r = ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + (u8)clk->cg_sel); + if (r) + goto disable_failed; + } + r = request_sysclk(false); + if (r) + goto disable_failed; + return; + +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +static struct clkops sysclk_ops = { + .enable = sysclk_enable, + .disable = sysclk_disable, +}; + +/* AB8500 UlpClk operations */ + +static int ab_ulpclk_enable(struct clk *clk) +{ + int err; + + if (clk->regulator == NULL) { + struct regulator *reg; + + reg = regulator_get(NULL, "v-intcore"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + clk->regulator = reg; + } + err = regulator_enable(clk->regulator); + if (err) + return err; + err = ab8500_sysctrl_clear(AB8500_SYSULPCLKCONF, + AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK); + if (err) + return err; + return ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_ULPCLKREQ); +} + +static void ab_ulpclk_disable(struct clk *clk) +{ + if (ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_ULPCLKREQ)) + goto out_err; + if (clk->regulator != NULL) { + if (regulator_disable(clk->regulator)) + goto out_err; + } + return; + +out_err: + pr_err("clock: %s failed to disable %s.\n", __func__, clk->name); +} + +static struct clkops ab_ulpclk_ops = { + .enable = ab_ulpclk_enable, + .disable = ab_ulpclk_disable, +}; + +/* AB8500 audio clock operations */ + +static int audioclk_enable(struct clk *clk) +{ + return ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_AUDIOCLKENA); +} + +static void audioclk_disable(struct clk *clk) +{ + if (ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_AUDIOCLKENA)) { + pr_err("clock: %s failed to disable %s.\n", __func__, + clk->name); + } +} + +static int audioclk_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent->ops == &sysclk_ops) { + return ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK); + } else if (parent->ops == &ab_ulpclk_ops) { + return ab8500_sysctrl_write(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK, + (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT)); + } else { + return -EINVAL; + } +} + +static struct clkops audioclk_ops = { + .enable = audioclk_enable, + .disable = audioclk_disable, + .set_parent = audioclk_set_parent, +}; + +/* Primary camera clock operations */ +static int clkout0_enable(struct clk *clk) +{ + int r; + + r = prcmu_config_clkout(0, PRCMU_CLKSRC_SYSCLK, 4); + if (r) + return r; + return nmk_config_pin(GPIO227_CLKOUT1, false); +} + +static void clkout0_disable(struct clk *clk) +{ + int r; + + r = nmk_config_pin(GPIO227_GPIO, false); + if (r) + goto disable_failed; + r = prcmu_config_clkout(0, PRCMU_CLKSRC_SYSCLK, 0); + if (!r) + return; +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +/* Touch screen/secondary camera clock operations. */ +static int clkout1_enable(struct clk *clk) +{ + int r; + + r = prcmu_config_clkout(1, PRCMU_CLKSRC_SYSCLK, 4); + if (r) + return r; + return nmk_config_pin(GPIO228_CLKOUT2, false); +} + +static void clkout1_disable(struct clk *clk) +{ + int r; + + r = nmk_config_pin(GPIO228_GPIO, false); + if (r) + goto disable_failed; + r = prcmu_config_clkout(1, PRCMU_CLKSRC_SYSCLK, 0); + if (!r) + return; +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +static struct clkops clkout0_ops = { + .enable = clkout0_enable, + .disable = clkout0_disable, +}; + +static struct clkops clkout1_ops = { + .enable = clkout1_enable, + .disable = clkout1_disable, +}; + +#define DEF_PER1_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U5500_CLKRST1_BASE, _cg_bit, &per1clk) +#define DEF_PER2_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U5500_CLKRST2_BASE, _cg_bit, &per2clk) +#define DEF_PER3_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U5500_CLKRST3_BASE, _cg_bit, &per3clk) +#define DEF_PER5_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U5500_CLKRST5_BASE, _cg_bit, &per5clk) +#define DEF_PER6_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U5500_CLKRST6_BASE, _cg_bit, &per6clk) + +#define DEF_PER1_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U5500_CLKRST1_BASE, _cg_bit, _parent) +#define DEF_PER2_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U5500_CLKRST2_BASE, _cg_bit, _parent) +#define DEF_PER3_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U5500_CLKRST3_BASE, _cg_bit, _parent) +#define DEF_PER5_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U5500_CLKRST5_BASE, _cg_bit, _parent) +#define DEF_PER6_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U5500_CLKRST6_BASE, _cg_bit, _parent) + +#define DEF_MTU_CLK(_cg_sel, _name, _bus_parent) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &mtu_clk_ops, \ + .cg_sel = _cg_sel, \ + .bus_parent = _bus_parent, \ + } + +/* Clock sources. */ + +static struct clk soc0_pll = { + .name = "soc0_pll", + .ops = &pll_clk_ops, +}; + +static struct clk soc1_pll = { + .name = "soc1_pll", + .ops = &pll_clk_ops, +}; + +static struct clk ddr_pll = { + .name = "ddr_pll", + .ops = &pll_clk_ops, +}; + +static struct clk ulp38m4 = { + .name = "ulp38m4", +}; + +static struct clk sysclk = { + .name = "sysclk", + .ops = &sysclk_ops, + .rate = 38400000, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk2 = { + .name = "sysclk2", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk3 = { + .name = "sysclk3", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk4 = { + .name = "sysclk4", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk rtc32k = { + .name = "rtc32k", + .rate = 32768, +}; + +static struct clk kbd32k = { + .name = "kbd32k", + .rate = 32768, +}; + +static struct clk clk_dummy = { + .name = "dummy", +}; + +static struct clk clk_msp1 = { + .name = "msp1", + .rate = 26000000, +}; + +static struct clk clkout0 = { + .name = "clkout0", + .ops = &clkout0_ops, + .parent = &sysclk, + .rate = 9600000, + .mutex = &sysclk_mutex, +}; + +static struct clk clkout1 = { + .name = "clkout1", + .ops = &clkout1_ops, + .parent = &sysclk, + .rate = 9600000, + .mutex = &sysclk_mutex, +}; + +static struct clk ab_ulpclk = { + .name = "ab_ulpclk", + .ops = &ab_ulpclk_ops, + .rate = 38400000, + .mutex = &ab_ulpclk_mutex, +}; + +static struct clk *audioclk_parents[] = { &sysclk, &ab_ulpclk, NULL }; + +static struct clk audioclk = { + .name = "audioclk", + .ops = &audioclk_ops, + .mutex = &audioclk_mutex, + .parent = &sysclk, + .parents = audioclk_parents, +}; + +static DEF_PRCMU_CLK(dmaclk, DB5500_PRCMU_DMACLK, 200000000); +static DEF_PRCMU_CLK(b2r2clk, DB5500_PRCMU_B2R2CLK, 200000000); +static DEF_PRCMU_CLK(sgaclk, DB5500_PRCMU_SGACLK, 199900000); +static DEF_PRCMU_CLK(uartclk, DB5500_PRCMU_UARTCLK, 36360000); +static DEF_PRCMU_CLK(msp02clk, DB5500_PRCMU_MSP02CLK, 13000000); +static DEF_PRCMU_CLK(i2cclk, DB5500_PRCMU_I2CCLK, 24000000); +static DEF_PRCMU_CLK(irdaclk, DB5500_PRCMU_IRDACLK, 48000000); +static DEF_PRCMU_CLK(irrcclk, DB5500_PRCMU_IRRCCLK, 48000000); +static DEF_PRCMU_CLK(rngclk, DB5500_PRCMU_RNGCLK, 26000000); +static DEF_PRCMU_CLK(pwmclk, DB5500_PRCMU_PWMCLK, 26000000); +static DEF_PRCMU_CLK(sdmmcclk, DB5500_PRCMU_SDMMCCLK, 100000000); +static DEF_PRCMU_CLK(per1clk, DB5500_PRCMU_PER1CLK, 133330000); +static DEF_PRCMU_CLK(per2clk, DB5500_PRCMU_PER2CLK, 133330000); +static DEF_PRCMU_CLK(per3clk, DB5500_PRCMU_PER3CLK, 133330000); +static DEF_PRCMU_CLK(per5clk, DB5500_PRCMU_PER5CLK, 133330000); +static DEF_PRCMU_CLK(per6clk, DB5500_PRCMU_PER6CLK, 133330000); +static DEF_PRCMU_CLK(hdmiclk, DB5500_PRCMU_HDMICLK, 26000000); +static DEF_PRCMU_CLK(apeatclk, DB5500_PRCMU_APEATCLK, 200000000); +static DEF_PRCMU_CLK(apetraceclk, DB5500_PRCMU_APETRACECLK, 266000000); +static DEF_PRCMU_CLK(mcdeclk, DB5500_PRCMU_MCDECLK, 160000000); +static DEF_PRCMU_CLK(tvclk, DB5500_PRCMU_TVCLK, 40000000); +static DEF_PRCMU_CLK(dsialtclk, DB5500_PRCMU_DSIALTCLK, 400000000); +static DEF_PRCMU_CLK(timclk, DB5500_PRCMU_TIMCLK, 3250000); + +/* PRCC PClocks */ + +static DEF_PER1_PCLK(0, p1_pclk0); +static DEF_PER1_PCLK(1, p1_pclk1); +static DEF_PER1_PCLK(2, p1_pclk2); +static DEF_PER1_PCLK(3, p1_pclk3); +static DEF_PER1_PCLK(4, p1_pclk4); +static DEF_PER1_PCLK(5, p1_pclk5); +static DEF_PER1_PCLK(6, p1_pclk6); + +static DEF_PER2_PCLK(0, p2_pclk0); +static DEF_PER2_PCLK(1, p2_pclk1); + +static DEF_PER3_PCLK(0, p3_pclk0); +static DEF_PER3_PCLK(1, p3_pclk1); +static DEF_PER3_PCLK(2, p3_pclk2); + +static DEF_PER5_PCLK(0, p5_pclk0); +static DEF_PER5_PCLK(1, p5_pclk1); +static DEF_PER5_PCLK(2, p5_pclk2); +static DEF_PER5_PCLK(3, p5_pclk3); +static DEF_PER5_PCLK(4, p5_pclk4); +static DEF_PER5_PCLK(5, p5_pclk5); +static DEF_PER5_PCLK(6, p5_pclk6); +static DEF_PER5_PCLK(7, p5_pclk7); +static DEF_PER5_PCLK(8, p5_pclk8); +static DEF_PER5_PCLK(9, p5_pclk9); +static DEF_PER5_PCLK(10, p5_pclk10); +static DEF_PER5_PCLK(11, p5_pclk11); +static DEF_PER5_PCLK(12, p5_pclk12); +static DEF_PER5_PCLK(13, p5_pclk13); +static DEF_PER5_PCLK(14, p5_pclk14); +static DEF_PER5_PCLK(15, p5_pclk15); + +static DEF_PER6_PCLK(0, p6_pclk0); +static DEF_PER6_PCLK(1, p6_pclk1); +static DEF_PER6_PCLK(2, p6_pclk2); +static DEF_PER6_PCLK(3, p6_pclk3); +static DEF_PER6_PCLK(4, p6_pclk4); +static DEF_PER6_PCLK(5, p6_pclk5); +static DEF_PER6_PCLK(6, p6_pclk6); +static DEF_PER6_PCLK(7, p6_pclk7); + +/* MSP0 */ +static DEF_PER1_KCLK(0, p1_msp0_kclk, &msp02clk); +static DEF_PER_CLK(p1_msp0_clk, &p1_pclk0, &p1_msp0_kclk); + +/* SDI0 */ +static DEF_PER1_KCLK(1, p1_sdi0_kclk, &sdmmcclk); +static DEF_PER_CLK(p1_sdi0_clk, &p1_pclk1, &p1_sdi0_kclk); + +/* SDI2 */ +static DEF_PER1_KCLK(2, p1_sdi2_kclk, &sdmmcclk); +static DEF_PER_CLK(p1_sdi2_clk, &p1_pclk2, &p1_sdi2_kclk); + +/* UART0 */ +static DEF_PER1_KCLK(3, p1_uart0_kclk, &uartclk); +static DEF_PER_CLK(p1_uart0_clk, &p1_pclk3, &p1_uart0_kclk); + +/* I2C1 */ +static DEF_PER1_KCLK(4, p1_i2c1_kclk, &i2cclk); +static DEF_PER_CLK(p1_i2c1_clk, &p1_pclk4, &p1_i2c1_kclk); + +/* PWM */ +static DEF_PER3_KCLK(0, p3_pwm_kclk, &pwmclk); +static DEF_PER_CLK(p3_pwm_clk, &p3_pclk1, &p3_pwm_kclk); + +/* KEYPAD */ +static DEF_PER3_KCLK(0, p3_keypad_kclk, &kbd32k); +static DEF_PER_CLK(p3_keypad_clk, &p3_pclk0, &p3_keypad_kclk); + +/* MSP2 */ +static DEF_PER5_KCLK(0, p5_msp2_kclk, &msp02clk); +static DEF_PER_CLK(p5_msp2_clk, &p5_pclk0, &p5_msp2_kclk); + +/* UART1 */ +static DEF_PER5_KCLK(1, p5_uart1_kclk, &uartclk); +static DEF_PER_CLK(p5_uart1_clk, &p5_pclk1, &p5_uart1_kclk); + +/* UART2 */ +static DEF_PER5_KCLK(2, p5_uart2_kclk, &uartclk); +static DEF_PER_CLK(p5_uart2_clk, &p5_pclk2, &p5_uart2_kclk); + +/* UART3 */ +static DEF_PER5_KCLK(3, p5_uart3_kclk, &uartclk); +static DEF_PER_CLK(p5_uart3_clk, &p5_pclk3, &p5_uart3_kclk); + +/* SDI1 */ +static DEF_PER5_KCLK(4, p5_sdi1_kclk, &sdmmcclk); +static DEF_PER_CLK(p5_sdi1_clk, &p5_pclk4, &p5_sdi1_kclk); + +/* SDI3 */ +static DEF_PER5_KCLK(5, p5_sdi3_kclk, &sdmmcclk); +static DEF_PER_CLK(p5_sdi3_clk, &p5_pclk5, &p5_sdi3_kclk); + +/* SDI4 */ +static DEF_PER5_KCLK(6, p5_sdi4_kclk, &sdmmcclk); +static DEF_PER_CLK(p5_sdi4_clk, &p5_pclk6, &p5_sdi4_kclk); + +/* I2C2 */ +static DEF_PER5_KCLK(7, p5_i2c2_kclk, &i2cclk); +static DEF_PER_CLK(p5_i2c2_clk, &p5_pclk7, &p5_i2c2_kclk); + +/* I2C3 */ +static DEF_PER5_KCLK(8, p5_i2c3_kclk, &i2cclk); +static DEF_PER_CLK(p5_i2c3_clk, &p5_pclk8, &p5_i2c3_kclk); + +/* IRRC */ +static DEF_PER5_KCLK(9, p5_irrc_kclk, &irrcclk); +static DEF_PER_CLK(p5_irrc_clk, &p5_pclk9, &p5_irrc_kclk); + +/* IRDA */ +static DEF_PER5_KCLK(10, p5_irda_kclk, &irdaclk); +static DEF_PER_CLK(p5_irda_clk, &p5_pclk10, &p5_irda_kclk); + +/* RNG */ +static DEF_PER6_KCLK(0, p6_rng_kclk, &rngclk); +static DEF_PER_CLK(p6_rng_clk, &p6_pclk0, &p6_rng_kclk); + +/* MTU:S */ + +/* MTU0 */ +static DEF_PER_CLK(p6_mtu0_clk, &p6_pclk6, &timclk); + +/* MTU1 */ +static DEF_PER_CLK(p6_mtu1_clk, &p6_pclk7, &timclk); + +static struct clk *db5500_dbg_clks[] = { + /* Clock sources */ + &soc0_pll, + &soc1_pll, + &ddr_pll, + &ulp38m4, + &sysclk, + &rtc32k, + + /* PRCMU clocks */ + &sgaclk, + &uartclk, + &msp02clk, + &i2cclk, + &irdaclk, + &irrcclk, + &sdmmcclk, + &per1clk, + &per2clk, + &per3clk, + &per5clk, + &per6clk, + &hdmiclk, + &apeatclk, + &apetraceclk, + &mcdeclk, + &dsialtclk, + &dmaclk, + &b2r2clk, + &tvclk, + &rngclk, + &pwmclk, + + /* Clock sources */ + &sysclk2, + &clkout0, + &clkout1, +}; + +#define CLK_LOOKUP(_clk, _dev_id, _con_id) \ + { .dev_id = _dev_id, .con_id = _con_id, .clk = &_clk } + +static struct clk_lookup u8500_common_clock_sources[] = { + CLK_LOOKUP(soc0_pll, NULL, "soc0_pll"), + CLK_LOOKUP(soc1_pll, NULL, "soc1_pll"), + CLK_LOOKUP(ddr_pll, NULL, "ddr_pll"), + CLK_LOOKUP(ulp38m4, NULL, "ulp38m4"), + CLK_LOOKUP(sysclk, NULL, "sysclk"), + CLK_LOOKUP(rtc32k, NULL, "clk32k"), + CLK_LOOKUP(sysclk, "ab8500-usb.0", "sysclk"), + CLK_LOOKUP(sysclk, "ab8500-codec.0", "sysclk"), + CLK_LOOKUP(ab_ulpclk, "ab8500-codec.0", "ulpclk"), + CLK_LOOKUP(audioclk, "ab8500-codec.0", "audioclk"), +}; + +static struct clk_lookup u8500_v2_sysclks[] = { + CLK_LOOKUP(sysclk2, NULL, "sysclk2"), + CLK_LOOKUP(sysclk3, NULL, "sysclk3"), + CLK_LOOKUP(sysclk4, NULL, "sysclk4"), +}; + +static struct clk_lookup db5500_prcmu_clocks[] = { + CLK_LOOKUP(sgaclk, "mali", NULL), + CLK_LOOKUP(uartclk, "UART", NULL), + CLK_LOOKUP(msp02clk, "MSP02", NULL), + CLK_LOOKUP(i2cclk, "I2C", NULL), + CLK_LOOKUP(sdmmcclk, "sdmmc", NULL), + CLK_LOOKUP(per1clk, "PERIPH1", NULL), + CLK_LOOKUP(per2clk, "PERIPH2", NULL), + CLK_LOOKUP(per3clk, "PERIPH3", NULL), + CLK_LOOKUP(per5clk, "PERIPH5", NULL), + CLK_LOOKUP(per6clk, "PERIPH6", NULL), + CLK_LOOKUP(hdmiclk, "mcde", "hdmi"), + CLK_LOOKUP(apeatclk, "apeat", NULL), + CLK_LOOKUP(apetraceclk, "apetrace", NULL), + CLK_LOOKUP(mcdeclk, "mcde", NULL), + CLK_LOOKUP(mcdeclk, "mcde", "mcde"), + CLK_LOOKUP(dmaclk, "dma40.0", NULL), + CLK_LOOKUP(b2r2clk, "b2r2", NULL), + CLK_LOOKUP(b2r2clk, "b2r2_bus", NULL), + CLK_LOOKUP(b2r2clk, "U8500-B2R2.0", NULL), + CLK_LOOKUP(tvclk, "tv", NULL), + CLK_LOOKUP(tvclk, "mcde", "tv"), +}; + +static struct clk_lookup db5500_prcc_clocks[] = { + CLK_LOOKUP(p1_msp0_clk, "MSP_I2S.0", NULL), + CLK_LOOKUP(p1_sdi0_clk, "sdi0", NULL), + CLK_LOOKUP(p1_sdi2_clk, "sdi2", NULL), + CLK_LOOKUP(p1_uart0_clk, "uart0", NULL), + CLK_LOOKUP(p1_i2c1_clk, "nmk-i2c.1", NULL), + CLK_LOOKUP(p1_pclk5, "gpio.0", NULL), + CLK_LOOKUP(p1_pclk5, "gpio.1", NULL), + CLK_LOOKUP(p1_pclk6, "fsmc", NULL), + + CLK_LOOKUP(p2_pclk0, "musb_hdrc.0", NULL), + CLK_LOOKUP(p2_pclk1, "gpio.2", NULL), + + CLK_LOOKUP(p3_keypad_clk, "db5500-keypad", NULL), + CLK_LOOKUP(p3_pwm_clk, "pwm", NULL), + CLK_LOOKUP(p3_pclk2, "gpio.4", NULL), + + CLK_LOOKUP(p5_msp2_clk, "MSP_I2S.2", NULL), + CLK_LOOKUP(p5_uart1_clk, "uart1", NULL), + CLK_LOOKUP(p5_uart2_clk, "uart2", NULL), + CLK_LOOKUP(p5_uart3_clk, "uart3", NULL), + CLK_LOOKUP(p5_sdi1_clk, "sdi1", NULL), + CLK_LOOKUP(p5_sdi3_clk, "sdi3", NULL), + CLK_LOOKUP(p5_sdi4_clk, "sdi4", NULL), + CLK_LOOKUP(p5_i2c2_clk, "nmk-i2c.2", NULL), + CLK_LOOKUP(p5_i2c3_clk, "nmk-i2c.3", NULL), + CLK_LOOKUP(p5_irrc_clk, "irrc", NULL), + CLK_LOOKUP(p5_irda_clk, "irda", NULL), + CLK_LOOKUP(p5_pclk11, "spi0", NULL), + CLK_LOOKUP(p5_pclk12, "spi1", NULL), + CLK_LOOKUP(p5_pclk13, "spi2", NULL), + CLK_LOOKUP(p5_pclk14, "spi3", NULL), + CLK_LOOKUP(p5_pclk15, "gpio.5", NULL), + CLK_LOOKUP(p5_pclk15, "gpio.6", NULL), + CLK_LOOKUP(p5_pclk15, "gpio.7", NULL), + + CLK_LOOKUP(p6_rng_clk, "rng", NULL), + CLK_LOOKUP(p6_pclk1, "cryp", NULL), + CLK_LOOKUP(p6_pclk2, "hash0", NULL), + CLK_LOOKUP(p6_pclk3, "pka", NULL), + CLK_LOOKUP(p6_pclk4, "hash1", NULL), + CLK_LOOKUP(p6_pclk5, "cfgreg", NULL), + CLK_LOOKUP(p6_mtu0_clk, "mtu0", NULL), + CLK_LOOKUP(p6_mtu1_clk, "mtu1", NULL), + + /* + * TODO: Clarify whether MSP1 need to be accessed from Linux, and who + * sets up the GPIOs. + */ + CLK_LOOKUP(clk_dummy, "gpio.3", NULL), + CLK_LOOKUP(clk_msp1, "MSP_I2S.1", NULL), +}; + +static struct clk_lookup u8500_v2_prcmu_clocks[] = { + CLK_LOOKUP(clkout0, "pri-cam", NULL), + CLK_LOOKUP(clkout1, "3-005c", NULL), + CLK_LOOKUP(clkout1, "3-005d", NULL), + CLK_LOOKUP(clkout1, "sec-cam", NULL), +}; + +static const char *db5500_boot_clk[] __initdata = { + "spi0", + "spi1", + "spi2", + "spi3", + "uart0", + "uart1", + "uart2", + "uart3", + "sdi0", + "sdi1", + "sdi2", + "sdi3", + "sdi4", +}; + +static struct clk *boot_clks[ARRAY_SIZE(db5500_boot_clk)] __initdata; + +static int __init db5500_boot_clk_disable(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(db5500_boot_clk); i++) { + clk_disable(boot_clks[i]); + clk_put(boot_clks[i]); + } + + return 0; +} +late_initcall_sync(db5500_boot_clk_disable); + +static void __init db5500_boot_clk_enable(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(db5500_boot_clk); i++) { + boot_clks[i] = clk_get_sys(db5500_boot_clk[i], NULL); + BUG_ON(IS_ERR(boot_clks[i])); + clk_enable(boot_clks[i]); + } +} + +static int db5500_prcmu_clk_enable(struct clk *clk) +{ + return db5500_prcmu_request_clock(clk->cg_sel, true); +} + +static void db5500_prcmu_clk_disable(struct clk *clk) +{ + if (db5500_prcmu_request_clock(clk->cg_sel, false)) { + pr_err("clock: %s failed to disable %s.\n", __func__, + clk->name); + } +} + +int __init db5500_clk_init(void) +{ + sysclk_ops.enable = NULL; + sysclk_ops.disable = NULL; + clkout0_ops.enable = NULL; + clkout0_ops.disable = NULL; + clkout1_ops.enable = NULL; + clkout1_ops.disable = NULL; + + prcmu_clk_ops.enable = db5500_prcmu_clk_enable; + prcmu_clk_ops.disable = db5500_prcmu_clk_disable; + + if (ux500_is_svp()) { + prcmu_clk_ops.enable = NULL; + prcmu_clk_ops.disable = NULL; + prcc_pclk_ops.enable = NULL; + prcc_pclk_ops.disable = NULL; + prcc_kclk_ops.enable = NULL; + prcc_kclk_ops.disable = NULL; + } + + clks_register(u8500_common_clock_sources, + ARRAY_SIZE(u8500_common_clock_sources)); + + clks_register(db5500_prcmu_clocks, ARRAY_SIZE(db5500_prcmu_clocks)); + clks_register(db5500_prcc_clocks, ARRAY_SIZE(db5500_prcc_clocks)); + + if (cpu_is_u8500v2()) { + clks_register(u8500_v2_sysclks, + ARRAY_SIZE(u8500_v2_sysclks)); + clks_register(u8500_v2_prcmu_clocks, + ARRAY_SIZE(u8500_v2_prcmu_clocks)); + } + + db5500_boot_clk_enable(); + + /* + * The following clks are shared with secure world. + * Currently this leads to a limitation where we need to + * enable them at all times. + */ + clk_enable(&p6_pclk1); + clk_enable(&p6_pclk2); + clk_enable(&p6_pclk3); + clk_enable(&p6_rng_clk); + + return 0; +} + +static int __init db5500_clk_debug_init(void) +{ + return dbx500_clk_debug_init(db5500_dbg_clks, + ARRAY_SIZE(db5500_dbg_clks)); +} +module_init(db5500_clk_debug_init); diff --git a/arch/arm/mach-ux500/clock-db8500.c b/arch/arm/mach-ux500/clock-db8500.c new file mode 100644 index 00000000000..611a2d24276 --- /dev/null +++ b/arch/arm/mach-ux500/clock-db8500.c @@ -0,0 +1,1289 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * Copyright (C) 2009 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/mfd/ab8500/sysctrl.h> +#include <linux/workqueue.h> +#include <linux/regulator/consumer.h> + +#include <plat/pincfg.h> + +#include <mach/hardware.h> +#include <mach/prcmu-fw-api.h> + +#include "clock.h" +#include "pins-db8500.h" + +#define PRCM_SDMMCCLK_MGT 0x024 +#define PRCM_TCR 0x1C8 +#define PRCM_TCR_STOPPED (1 << 16) +#define PRCM_TCR_DOZE_MODE (1 << 17) +#define SD_CLK_DIV_MASK 0x1F +#define SD_CLK_DIV_VAL 8 + +static DEFINE_MUTEX(soc1_pll_mutex); +static DEFINE_MUTEX(sysclk_mutex); +static DEFINE_MUTEX(ab_ulpclk_mutex); +static DEFINE_MUTEX(audioclk_mutex); + +static struct delayed_work sysclk_disable_work; + +/* PLL operations. */ + +static int clk_pllsrc_enable(struct clk *clk) +{ + /* To enable pll */ + return 0; +} + +static void clk_pllsrc_disable(struct clk *clk) +{ + /* To disable pll */ +} + +static struct clkops pll_clk_ops = { + .enable = clk_pllsrc_enable, + .disable = clk_pllsrc_disable, +}; + +/* SysClk operations. */ + +static int request_sysclk(bool enable) +{ + static int requests; + + if ((enable && (requests++ == 0)) || (!enable && (--requests == 0))) + return prcmu_request_clock(PRCMU_SYSCLK, enable); + return 0; +} + +static int sysclk_enable(struct clk *clk) +{ + static bool swat_enable; + int r; + + if (!swat_enable) { + r = ab8500_sysctrl_set(AB8500_SWATCTRL, + AB8500_SWATCTRL_SWATENABLE); + if (r) + return r; + + swat_enable = true; + } + + r = request_sysclk(true); + if (r) + return r; + + if (clk->cg_sel) { + r = ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, (u8)clk->cg_sel); + if (r) + (void)request_sysclk(false); + } + return r; +} + +static void sysclk_disable(struct clk *clk) +{ + int r; + + if (clk->cg_sel) { + r = ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + (u8)clk->cg_sel); + if (r) + goto disable_failed; + } + r = request_sysclk(false); + if (r) + goto disable_failed; + return; + +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +static struct clkops sysclk_ops = { + .enable = sysclk_enable, + .disable = sysclk_disable, +}; + +/* AB8500 UlpClk operations */ + +static int ab_ulpclk_enable(struct clk *clk) +{ + int err; + + if (clk->regulator == NULL) { + struct regulator *reg; + + reg = regulator_get(NULL, "v-intcore"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + clk->regulator = reg; + } + err = regulator_enable(clk->regulator); + if (err) + return err; + err = ab8500_sysctrl_clear(AB8500_SYSULPCLKCONF, + AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK); + if (err) + return err; + return ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, + (AB8500_SYSULPCLKCTRL1_ULPCLKREQ | + AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK)); +} + +static void ab_ulpclk_disable(struct clk *clk) +{ + if (ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_ULPCLKREQ)) + goto out_err; + if (clk->regulator != NULL) { + if (regulator_disable(clk->regulator)) + goto out_err; + } + return; + +out_err: + pr_err("clock: %s failed to disable %s.\n", __func__, clk->name); +} + +static struct clkops ab_ulpclk_ops = { + .enable = ab_ulpclk_enable, + .disable = ab_ulpclk_disable, +}; + +/* AB8500 audio clock operations */ + +static int audioclk_enable(struct clk *clk) +{ + return ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_AUDIOCLKENA); +} + +static void audioclk_disable(struct clk *clk) +{ + if (ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + AB8500_SYSULPCLKCTRL1_AUDIOCLKENA)) { + pr_err("clock: %s failed to disable %s.\n", __func__, + clk->name); + } +} + +static struct clkops audioclk_ops = { + .enable = audioclk_enable, + .disable = audioclk_disable, +}; + +/* Primary camera clock operations */ +static int clkout0_enable(struct clk *clk) +{ + int r; + + r = prcmu_config_clkout(0, PRCMU_CLKSRC_SYSCLK, 4); + if (r) + return r; + return nmk_config_pin(GPIO227_CLKOUT1, false); +} + +static void clkout0_disable(struct clk *clk) +{ + int r; + + r = nmk_config_pin(GPIO227_GPIO, false); + if (r) + goto disable_failed; + r = prcmu_config_clkout(0, PRCMU_CLKSRC_SYSCLK, 0); + if (!r) + return; +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +/* Touch screen/secondary camera clock operations. */ +static int clkout1_enable(struct clk *clk) +{ + int r; + + r = prcmu_config_clkout(1, PRCMU_CLKSRC_SYSCLK, 4); + if (r) + return r; + return nmk_config_pin(GPIO228_CLKOUT2, false); +} + +static void clkout1_disable(struct clk *clk) +{ + int r; + + r = nmk_config_pin(GPIO228_GPIO, false); + if (r) + goto disable_failed; + r = prcmu_config_clkout(1, PRCMU_CLKSRC_SYSCLK, 0); + if (!r) + return; +disable_failed: + pr_err("clock: failed to disable %s.\n", clk->name); +} + +static struct clkops clkout0_ops = { + .enable = clkout0_enable, + .disable = clkout0_disable, +}; + +static struct clkops clkout1_ops = { + .enable = clkout1_enable, + .disable = clkout1_disable, +}; + +#define DEF_PER1_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST1_BASE, _cg_bit, &per1clk) +#define DEF_PER2_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST2_BASE, _cg_bit, &per2clk) +#define DEF_PER3_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST3_BASE, _cg_bit, &per3clk) +#define DEF_PER5_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST5_BASE, _cg_bit, &per5clk) +#define DEF_PER6_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST6_BASE, _cg_bit, &per6clk) +#define DEF_PER7_PCLK(_cg_bit, _name) \ + DEF_PRCC_PCLK(_name, U8500_CLKRST7_BASE_ED, _cg_bit, &per7clk) + +#define DEF_PER1_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST1_BASE, _cg_bit, _parent) +#define DEF_PER2_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST2_BASE, _cg_bit, _parent) +#define DEF_PER3_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST3_BASE, _cg_bit, _parent) +#define DEF_PER5_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST5_BASE, _cg_bit, _parent) +#define DEF_PER6_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST6_BASE, _cg_bit, _parent) +#define DEF_PER7_KCLK(_cg_bit, _name, _parent) \ + DEF_PRCC_KCLK(_name, U8500_CLKRST7_BASE_ED, _cg_bit, _parent) + +#define DEF_MTU_CLK(_cg_sel, _name, _bus_parent) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &mtu_clk_ops, \ + .cg_sel = _cg_sel, \ + .bus_parent = _bus_parent, \ + } + +/* Clock sources. */ + +static struct clk soc0_pll = { + .name = "soc0_pll", + .ops = &pll_clk_ops, +}; + +static struct clk soc1_pll = { + .name = "soc1_pll", + .ops = &prcmu_clk_ops, + .cg_sel = PRCMU_PLLSOC1, + .mutex = &soc1_pll_mutex, +}; + +static struct clk ddr_pll = { + .name = "ddr_pll", + .ops = &pll_clk_ops, +}; + +static struct clk ulp38m4 = { + .name = "ulp38m4", +}; + +static struct clk sysclk = { + .name = "sysclk", + .ops = &sysclk_ops, + .rate = 38400000, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk2 = { + .name = "sysclk2", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk3 = { + .name = "sysclk3", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk sysclk4 = { + .name = "sysclk4", + .ops = &sysclk_ops, + .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, + .mutex = &sysclk_mutex, +}; + +static struct clk rtc32k = { + .name = "rtc32k", + .rate = 32768, +}; + +static struct clk clkout0 = { + .name = "clkout0", + .ops = &clkout0_ops, + .parent = &sysclk, + .rate = 9600000, + .mutex = &sysclk_mutex, +}; + +static struct clk clkout1 = { + .name = "clkout1", + .ops = &clkout1_ops, + .parent = &sysclk, + .rate = 9600000, + .mutex = &sysclk_mutex, +}; + +static struct clk ab_ulpclk = { + .name = "ab_ulpclk", + .ops = &ab_ulpclk_ops, + .rate = 38400000, + .mutex = &ab_ulpclk_mutex, +}; + +static struct clk *audioclk_parents[] = { &sysclk, &ab_ulpclk, NULL }; + +static struct clk audioclk = { + .name = "audioclk", + .ops = &audioclk_ops, + .mutex = &audioclk_mutex, + .parent = &sysclk, + .parents = audioclk_parents, +}; + +static DEF_PRCMU_CLK(sgaclk, PRCMU_SGACLK, 320000000); +static DEF_PRCMU_CLK(uartclk, PRCMU_UARTCLK, 38400000); +static DEF_PRCMU_CLK(msp02clk, PRCMU_MSP02CLK, 19200000); +static DEF_PRCMU_CLK(msp1clk, PRCMU_MSP1CLK, 19200000); +static DEF_PRCMU_CLK(i2cclk, PRCMU_I2CCLK, 24000000); +static DEF_PRCMU_CLK(slimclk, PRCMU_SLIMCLK, 19200000); +static DEF_PRCMU_CLK(per1clk, PRCMU_PER1CLK, 133330000); +static DEF_PRCMU_CLK(per2clk, PRCMU_PER2CLK, 133330000); +static DEF_PRCMU_CLK(per3clk, PRCMU_PER3CLK, 133330000); +static DEF_PRCMU_CLK(per5clk, PRCMU_PER5CLK, 133330000); +static DEF_PRCMU_CLK(per6clk, PRCMU_PER6CLK, 133330000); +static DEF_PRCMU_CLK(per7clk, PRCMU_PER7CLK, 100000000); +static DEF_PRCMU_CLK(lcdclk, PRCMU_LCDCLK, 48000000); +static DEF_PRCMU_OPP100_CLK(bmlclk, PRCMU_BMLCLK, 200000000); +static DEF_PRCMU_CLK(hsitxclk, PRCMU_HSITXCLK, 100000000); +static DEF_PRCMU_CLK(hsirxclk, PRCMU_HSIRXCLK, 200000000); +static DEF_PRCMU_CLK(hdmiclk, PRCMU_HDMICLK, 76800000); +static DEF_PRCMU_CLK(apeatclk, PRCMU_APEATCLK, 160000000); +static DEF_PRCMU_CLK(apetraceclk, PRCMU_APETRACECLK, 160000000); +static DEF_PRCMU_CLK(mcdeclk, PRCMU_MCDECLK, 160000000); +static DEF_PRCMU_OPP100_CLK(ipi2cclk, PRCMU_IPI2CCLK, 24000000); +static DEF_PRCMU_CLK(dsialtclk, PRCMU_DSIALTCLK, 384000000); +static DEF_PRCMU_CLK(dmaclk, PRCMU_DMACLK, 200000000); +static DEF_PRCMU_CLK(b2r2clk, PRCMU_B2R2CLK, 200000000); +static DEF_PRCMU_CLK(tvclk, PRCMU_TVCLK, 76800000); +/* TODO: For SSPCLK, the spec says 24MHz, while the old driver says 48MHz. */ +static DEF_PRCMU_CLK(sspclk, PRCMU_SSPCLK, 24000000); +static DEF_PRCMU_CLK(rngclk, PRCMU_RNGCLK, 19200000); +static DEF_PRCMU_CLK(uiccclk, PRCMU_UICCCLK, 48000000); +static DEF_PRCMU_CLK(timclk, PRCMU_TIMCLK, 2400000); +static DEF_PRCMU_CLK(sdmmcclk, PRCMU_SDMMCCLK, 50000000); + +/* PRCC PClocks */ + +static DEF_PER1_PCLK(0, p1_pclk0); +static DEF_PER1_PCLK(1, p1_pclk1); +static DEF_PER1_PCLK(2, p1_pclk2); +static DEF_PER1_PCLK(3, p1_pclk3); +static DEF_PER1_PCLK(4, p1_pclk4); +static DEF_PER1_PCLK(5, p1_pclk5); +static DEF_PER1_PCLK(6, p1_pclk6); +static DEF_PER1_PCLK(7, p1_pclk7); +static DEF_PER1_PCLK(8, p1_pclk8); +static DEF_PER1_PCLK(9, p1_pclk9); +static DEF_PER1_PCLK(10, p1_pclk10); +static DEF_PER1_PCLK(11, p1_pclk11); + +static DEF_PER2_PCLK(0, p2_pclk0); +static DEF_PER2_PCLK(1, p2_pclk1); +static DEF_PER2_PCLK(2, p2_pclk2); +static DEF_PER2_PCLK(3, p2_pclk3); +static DEF_PER2_PCLK(4, p2_pclk4); +static DEF_PER2_PCLK(5, p2_pclk5); +static DEF_PER2_PCLK(6, p2_pclk6); +static DEF_PER2_PCLK(7, p2_pclk7); +static DEF_PER2_PCLK(8, p2_pclk8); +static DEF_PER2_PCLK(9, p2_pclk9); +static DEF_PER2_PCLK(10, p2_pclk10); +static DEF_PER2_PCLK(11, p2_pclk11); +static DEF_PER2_PCLK(12, p2_pclk12); + +static DEF_PER3_PCLK(0, p3_pclk0); +static DEF_PER3_PCLK(1, p3_pclk1); +static DEF_PER3_PCLK(2, p3_pclk2); +static DEF_PER3_PCLK(3, p3_pclk3); +static DEF_PER3_PCLK(4, p3_pclk4); +static DEF_PER3_PCLK(5, p3_pclk5); +static DEF_PER3_PCLK(6, p3_pclk6); +static DEF_PER3_PCLK(7, p3_pclk7); +static DEF_PER3_PCLK(8, p3_pclk8); + +static DEF_PER5_PCLK(0, p5_pclk0); +static DEF_PER5_PCLK(1, p5_pclk1); + +static DEF_PER6_PCLK(0, p6_pclk0); +static DEF_PER6_PCLK(1, p6_pclk1); +static DEF_PER6_PCLK(2, p6_pclk2); +static DEF_PER6_PCLK(3, p6_pclk3); +static DEF_PER6_PCLK(4, p6_pclk4); +static DEF_PER6_PCLK(5, p6_pclk5); +static DEF_PER6_PCLK(6, p6_pclk6); +static DEF_PER6_PCLK(7, p6_pclk7); + +static DEF_PER7_PCLK(0, p7_pclk0); +static DEF_PER7_PCLK(1, p7_pclk1); +static DEF_PER7_PCLK(2, p7_pclk2); +static DEF_PER7_PCLK(3, p7_pclk3); +static DEF_PER7_PCLK(4, p7_pclk4); + +/* UART0 */ +static DEF_PER1_KCLK(0, p1_uart0_kclk, &uartclk); +static DEF_PER_CLK(p1_uart0_clk, &p1_pclk0, &p1_uart0_kclk); + +/* UART1 */ +static DEF_PER1_KCLK(1, p1_uart1_kclk, &uartclk); +static DEF_PER_CLK(p1_uart1_clk, &p1_pclk1, &p1_uart1_kclk); + +/* I2C1 */ +static DEF_PER1_KCLK(2, p1_i2c1_kclk, &i2cclk); +static DEF_PER_CLK(p1_i2c1_clk, &p1_pclk2, &p1_i2c1_kclk); + +/* MSP0 */ +static DEF_PER1_KCLK(3, p1_msp0_kclk, &msp02clk); +static DEF_PER_CLK(p1_msp0_clk, &p1_pclk3, &p1_msp0_kclk); + +/* MSP1 */ +static DEF_PER1_KCLK(4, p1_msp1_kclk, &msp1clk); +static DEF_PER_CLK(p1_msp1_clk, &p1_pclk4, &p1_msp1_kclk); + +static DEF_PER1_KCLK(4, p1_msp1_ed_kclk, &msp02clk); +static DEF_PER_CLK(p1_msp1_ed_clk, &p1_pclk4, &p1_msp1_ed_kclk); + +/* SDI0 */ +static DEF_PER1_KCLK(5, p1_sdi0_kclk, &sdmmcclk); +static DEF_PER_CLK(p1_sdi0_clk, &p1_pclk5, &p1_sdi0_kclk); + +/* I2C2 */ +static DEF_PER1_KCLK(6, p1_i2c2_kclk, &i2cclk); +static DEF_PER_CLK(p1_i2c2_clk, &p1_pclk6, &p1_i2c2_kclk); + +/* SLIMBUS0 */ +static DEF_PER1_KCLK(3, p1_slimbus0_kclk, &slimclk); +static DEF_PER_CLK(p1_slimbus0_clk, &p1_pclk8, &p1_slimbus0_kclk); + +/* I2C4 */ +static DEF_PER1_KCLK(9, p1_i2c4_kclk, &i2cclk); +static DEF_PER_CLK(p1_i2c4_clk, &p1_pclk10, &p1_i2c4_kclk); + +/* MSP3 */ +static DEF_PER1_KCLK(10, p1_msp3_kclk, &msp1clk); +static DEF_PER_CLK(p1_msp3_clk, &p1_pclk11, &p1_msp3_kclk); + +/* I2C3 */ +static DEF_PER2_KCLK(0, p2_i2c3_kclk, &i2cclk); +static DEF_PER_CLK(p2_i2c3_clk, &p2_pclk0, &p2_i2c3_kclk); + +/* SDI4 */ +static DEF_PER2_KCLK(2, p2_sdi4_kclk, &sdmmcclk); +static DEF_PER_CLK(p2_sdi4_clk, &p2_pclk4, &p2_sdi4_kclk); + +/* MSP2 */ +static DEF_PER2_KCLK(3, p2_msp2_kclk, &msp02clk); +static DEF_PER_CLK(p2_msp2_clk, &p2_pclk5, &p2_msp2_kclk); + +static DEF_PER2_KCLK(4, p2_msp2_ed_kclk, &msp02clk); +static DEF_PER_CLK(p2_msp2_ed_clk, &p2_pclk6, &p2_msp2_ed_kclk); + +/* SDI1 */ +static DEF_PER2_KCLK(4, p2_sdi1_kclk, &sdmmcclk); +static DEF_PER_CLK(p2_sdi1_clk, &p2_pclk6, &p2_sdi1_kclk); + +/* These are probably broken now. */ +static DEF_PER2_KCLK(5, p2_sdi1_ed_kclk, &sdmmcclk); +static DEF_PER_CLK(p2_sdi1_ed_clk, &p2_pclk7, &p2_sdi1_ed_kclk); + +/* SDI3 */ +static DEF_PER2_KCLK(5, p2_sdi3_kclk, &sdmmcclk); +static DEF_PER_CLK(p2_sdi3_clk, &p2_pclk7, &p2_sdi3_kclk); + +/* These are probably broken now. */ +static DEF_PER2_KCLK(6, p2_sdi3_ed_kclk, &sdmmcclk); +static DEF_PER_CLK(p2_sdi3_ed_clk, &p2_pclk8, &p2_sdi3_ed_kclk); + +/* HSIR */ +static DEF_PER2_KCLK(6, p2_ssirx_kclk, &hsirxclk); + +/* HSIT */ +static DEF_PER2_KCLK(7, p2_ssitx_kclk, &hsitxclk); + +/* SSP0 */ +static DEF_PER3_KCLK(1, p3_ssp0_kclk, &sspclk); +static DEF_PER_CLK(p3_ssp0_clk, &p3_pclk1, &p3_ssp0_kclk); + +static DEF_PER3_KCLK(1, p3_ssp0_ed_kclk, &i2cclk); +static DEF_PER_CLK(p3_ssp0_ed_clk, &p3_pclk1, &p3_ssp0_ed_kclk); + +/* SSP1 */ +static DEF_PER3_KCLK(2, p3_ssp1_kclk, &sspclk); +static DEF_PER_CLK(p3_ssp1_clk, &p3_pclk2, &p3_ssp1_kclk); + +static DEF_PER3_KCLK(2, p3_ssp1_ed_kclk, &i2cclk); +static DEF_PER_CLK(p3_ssp1_ed_clk, &p3_pclk2, &p3_ssp1_ed_kclk); + +/* I2C0 */ +static DEF_PER3_KCLK(3, p3_i2c0_kclk, &i2cclk); +static DEF_PER_CLK(p3_i2c0_clk, &p3_pclk3, &p3_i2c0_kclk); + +/* SDI2 */ +static DEF_PER3_KCLK(4, p3_sdi2_kclk, &sdmmcclk); +static DEF_PER_CLK(p3_sdi2_clk, &p3_pclk4, &p3_sdi2_kclk); + +/* SKE */ +static DEF_PER3_KCLK(5, p3_ske_kclk, &rtc32k); +static DEF_PER_CLK(p3_ske_clk, &p3_pclk5, &p3_ske_kclk); + +/* UART2 */ +static DEF_PER3_KCLK(6, p3_uart2_kclk, &uartclk); +static DEF_PER_CLK(p3_uart2_clk, &p3_pclk6, &p3_uart2_kclk); + +/* SDI5 */ +static DEF_PER3_KCLK(7, p3_sdi5_kclk, &sdmmcclk); +static DEF_PER_CLK(p3_sdi5_clk, &p3_pclk7, &p3_sdi5_kclk); + +/* USB */ +static DEF_PER5_KCLK(0, p5_usb_ed_kclk, &i2cclk); +static DEF_PER_CLK(p5_usb_ed_clk, &p5_pclk0, &p5_usb_ed_kclk); + +/* RNG */ +static DEF_PER6_KCLK(0, p6_rng_kclk, &rngclk); +static DEF_PER_CLK(p6_rng_clk, &p6_pclk0, &p6_rng_kclk); + +static DEF_PER6_KCLK(0, p6_rng_ed_kclk, &i2cclk); +static DEF_PER_CLK(p6_rng_ed_clk, &p6_pclk0, &p6_rng_ed_kclk); + + +/* MTU:S */ + +/* MTU0 */ +static DEF_PER_CLK(p6_mtu0_clk, &p6_pclk6, &timclk); +static DEF_PER_CLK(p7_mtu0_ed_clk, &p7_pclk2, &timclk); + +/* MTU1 */ +static DEF_PER_CLK(p6_mtu1_clk, &p6_pclk7, &timclk); +static DEF_PER_CLK(p7_mtu1_ed_clk, &p7_pclk3, &timclk); + +#ifdef CONFIG_DEBUG_FS + +struct clk_debug_info { + struct clk *clk; + struct dentry *dir; + struct dentry *enable; + struct dentry *requests; + int enabled; +}; + +static struct dentry *clk_dir; +static struct dentry *clk_show; +static struct dentry *clk_show_enabled_only; + +static struct clk_debug_info dbg_clks[] = { + /* Clock sources */ + { .clk = &soc0_pll, }, + { .clk = &soc1_pll, }, + { .clk = &ddr_pll, }, + { .clk = &ulp38m4, }, + { .clk = &sysclk, }, + { .clk = &rtc32k, }, + /* PRCMU clocks */ + { .clk = &sgaclk, }, + { .clk = &uartclk, }, + { .clk = &msp02clk, }, + { .clk = &msp1clk, }, + { .clk = &i2cclk, }, + { .clk = &sdmmcclk, }, + { .clk = &slimclk, }, + { .clk = &per1clk, }, + { .clk = &per2clk, }, + { .clk = &per3clk, }, + { .clk = &per5clk, }, + { .clk = &per6clk, }, + { .clk = &per7clk, }, + { .clk = &lcdclk, }, + { .clk = &bmlclk, }, + { .clk = &hsitxclk, }, + { .clk = &hsirxclk, }, + { .clk = &hdmiclk, }, + { .clk = &apeatclk, }, + { .clk = &apetraceclk, }, + { .clk = &mcdeclk, }, + { .clk = &ipi2cclk, }, + { .clk = &dsialtclk, }, + { .clk = &dmaclk, }, + { .clk = &b2r2clk, }, + { .clk = &tvclk, }, + { .clk = &sspclk, }, + { .clk = &rngclk, }, + { .clk = &uiccclk, }, +}; + +static struct clk_debug_info dbg_clks_v2[] = { + /* Clock sources */ + { .clk = &sysclk2, }, + { .clk = &clkout0, }, + { .clk = &clkout1, }, +}; + +static int clk_show_print(struct seq_file *s, void *p) +{ + int i; + int enabled_only = (int)s->private; + + seq_printf(s, "\n%-20s %s\n", "name", "enabled (kernel + debug)"); + for (i = 0; i < ARRAY_SIZE(dbg_clks); i++) { + if (enabled_only && !dbg_clks[i].clk->enabled) + continue; + seq_printf(s, + "%-20s %5d + %d\n", + dbg_clks[i].clk->name, + dbg_clks[i].clk->enabled - dbg_clks[i].enabled, + dbg_clks[i].enabled); + } + if (cpu_is_u8500v2()) { + for (i = 0; i < ARRAY_SIZE(dbg_clks_v2); i++) { + if (enabled_only && !dbg_clks_v2[i].clk->enabled) + continue; + seq_printf(s, + "%-20s %5d + %d\n", + dbg_clks_v2[i].clk->name, + (dbg_clks_v2[i].clk->enabled - + dbg_clks_v2[i].enabled), + dbg_clks_v2[i].enabled); + } + } + + return 0; +} + +static int clk_show_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_show_print, inode->i_private); +} + +static int clk_enable_print(struct seq_file *s, void *p) +{ + struct clk_debug_info *cdi = s->private; + + return seq_printf(s, "%d\n", cdi->enabled); +} + +static int clk_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_enable_print, inode->i_private); +} + +static ssize_t clk_enable_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct clk_debug_info *cdi; + char buf[32]; + ssize_t buf_size; + long user_val; + int err; + + cdi = ((struct seq_file *)(file->private_data))->private; + + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = '\0'; + + err = strict_strtol(buf, 0, &user_val); + if (err) + return -EINVAL; + if ((user_val > 0) && (!cdi->enabled)) { + err = clk_enable(cdi->clk); + if (err) { + pr_err("clock: clk_enable(%s) failed.\n", + cdi->clk->name); + return -EFAULT; + } + cdi->enabled = 1; + } else if ((user_val <= 0) && (cdi->enabled)) { + clk_disable(cdi->clk); + cdi->enabled = 0; + } + return buf_size; +} + +static int clk_requests_print(struct seq_file *s, void *p) +{ + struct clk_debug_info *cdi = s->private; + + return seq_printf(s, "%d\n", cdi->clk->enabled); +} + +static int clk_requests_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_requests_print, inode->i_private); +} + +static const struct file_operations clk_enable_fops = { + .open = clk_enable_open, + .write = clk_enable_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations clk_requests_fops = { + .open = clk_requests_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations clk_show_fops = { + .open = clk_show_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int create_clk_dirs(struct clk_debug_info *cdi, int size) +{ + int i; + + for (i = 0; i < size; i++) { + cdi[i].dir = debugfs_create_dir(cdi[i].clk->name, clk_dir); + if (!cdi[i].dir) + goto no_dir; + } + + for (i = 0; i < size; i++) { + cdi[i].enable = debugfs_create_file("enable", + (S_IRUGO | S_IWUGO), + cdi[i].dir, &cdi[i], + &clk_enable_fops); + if (!cdi[i].enable) + goto no_enable; + } + for (i = 0; i < size; i++) { + cdi[i].requests = debugfs_create_file("requests", S_IRUGO, + cdi[i].dir, &cdi[i], + &clk_requests_fops); + if (!cdi[i].requests) + goto no_requests; + } + return 0; + +no_requests: + while (i--) + debugfs_remove(cdi[i].requests); + i = size; +no_enable: + while (i--) + debugfs_remove(cdi[i].enable); + i = size; +no_dir: + while (i--) + debugfs_remove(cdi[i].dir); + + return -ENOMEM; +} + +static void remove_clk_dirs(struct clk_debug_info *cdi, int size) +{ + int i; + for (i = 0; i < size; i++) { + debugfs_remove(cdi[i].requests); + debugfs_remove(cdi[i].enable); + debugfs_remove(cdi[i].dir); + } +} + +static int __init clk_debug_init(void) +{ + clk_dir = debugfs_create_dir("clk", NULL); + if (!clk_dir) + goto no_dir; + + clk_show = debugfs_create_file("show", S_IRUGO, clk_dir, (void *)0, + &clk_show_fops); + if (!clk_show) + goto no_show; + + clk_show_enabled_only = debugfs_create_file("show-enabled-only", + S_IRUGO, clk_dir, (void *)1, + &clk_show_fops); + if (!clk_show_enabled_only) + goto no_enabled_only; + + if (create_clk_dirs(&dbg_clks[0], ARRAY_SIZE(dbg_clks))) + goto no_clks; + + if (cpu_is_u8500v2()) { + if (create_clk_dirs(&dbg_clks_v2[0], ARRAY_SIZE(dbg_clks_v2))) + goto common_clks; + } + return 0; + +common_clks: + remove_clk_dirs(&dbg_clks[0], ARRAY_SIZE(dbg_clks)); +no_clks: + debugfs_remove(clk_show_enabled_only); +no_enabled_only: + debugfs_remove(clk_show); +no_show: + debugfs_remove(clk_dir); +no_dir: + return -ENOMEM; +} + +static void __exit clk_debug_exit(void) +{ + remove_clk_dirs(&dbg_clks[0], ARRAY_SIZE(dbg_clks)); + if (cpu_is_u8500v2()) + remove_clk_dirs(&dbg_clks_v2[0], ARRAY_SIZE(dbg_clks_v2)); + + debugfs_remove(clk_show); + debugfs_remove(clk_show_enabled_only); + debugfs_remove(clk_dir); +} + +subsys_initcall(clk_debug_init); +module_exit(clk_debug_exit); +#endif /* CONFIG_DEBUG_FS */ + +/* + * TODO: Ensure names match with devices and then remove unnecessary entries + * when all drivers use the clk API. + */ + +#define CLK_LOOKUP(_clk, _dev_id, _con_id) \ + { .dev_id = _dev_id, .con_id = _con_id, .clk = &_clk } + +static struct clk_lookup u8500_common_clock_sources[] = { + CLK_LOOKUP(soc0_pll, NULL, "soc0_pll"), + CLK_LOOKUP(soc1_pll, NULL, "soc1_pll"), + CLK_LOOKUP(ddr_pll, NULL, "ddr_pll"), + CLK_LOOKUP(ulp38m4, NULL, "ulp38m4"), + CLK_LOOKUP(sysclk, NULL, "sysclk"), + CLK_LOOKUP(rtc32k, NULL, "clk32k"), + CLK_LOOKUP(sysclk, "ab8500-usb.0", "sysclk"), + CLK_LOOKUP(sysclk, "ab8500-codec.0", "sysclk"), + CLK_LOOKUP(ab_ulpclk, "ab8500-codec.0", "ulpclk"), + CLK_LOOKUP(audioclk, "ab8500-codec.0", "audioclk"), + CLK_LOOKUP(ab_ulpclk, "ab8500-pwm.1", NULL), + CLK_LOOKUP(ab_ulpclk, "ab8500-pwm.2", NULL), + CLK_LOOKUP(ab_ulpclk, "ab8500-pwm.3", NULL), +}; + +static struct clk_lookup u8500_v2_sysclks[] = { + CLK_LOOKUP(sysclk2, NULL, "sysclk2"), + CLK_LOOKUP(sysclk3, NULL, "sysclk3"), + CLK_LOOKUP(sysclk4, NULL, "sysclk4"), +}; + +static struct clk_lookup u8500_common_prcmu_clocks[] = { + CLK_LOOKUP(sgaclk, "mali", NULL), + CLK_LOOKUP(uartclk, "UART", NULL), + CLK_LOOKUP(msp02clk, "MSP02", NULL), + CLK_LOOKUP(i2cclk, "I2C", NULL), + CLK_LOOKUP(sdmmcclk, "sdmmc", NULL), + CLK_LOOKUP(slimclk, "slim", NULL), + CLK_LOOKUP(per1clk, "PERIPH1", NULL), + CLK_LOOKUP(per2clk, "PERIPH2", NULL), + CLK_LOOKUP(per3clk, "PERIPH3", NULL), + CLK_LOOKUP(per5clk, "PERIPH5", NULL), + CLK_LOOKUP(per6clk, "PERIPH6", NULL), + CLK_LOOKUP(per7clk, "PERIPH7", NULL), + CLK_LOOKUP(lcdclk, "lcd", NULL), + CLK_LOOKUP(bmlclk, "bml", NULL), + CLK_LOOKUP(p2_ssitx_kclk, "ste_hsi.0", "hsit_hsitxclk"), + CLK_LOOKUP(p2_ssirx_kclk, "ste_hsi.0", "hsir_hsirxclk"), + CLK_LOOKUP(lcdclk, "mcde", "lcd"), + CLK_LOOKUP(hdmiclk, "hdmi", NULL), + CLK_LOOKUP(hdmiclk, "mcde", "hdmi"), + CLK_LOOKUP(apeatclk, "apeat", NULL), + CLK_LOOKUP(apetraceclk, "apetrace", NULL), + CLK_LOOKUP(mcdeclk, "mcde", NULL), + CLK_LOOKUP(mcdeclk, "mcde", "mcde"), + CLK_LOOKUP(ipi2cclk, "ipi2", NULL), + CLK_LOOKUP(dmaclk, "dma40.0", NULL), + CLK_LOOKUP(b2r2clk, "b2r2", NULL), + CLK_LOOKUP(b2r2clk, "b2r2_bus", NULL), + CLK_LOOKUP(b2r2clk, "U8500-B2R2.0", NULL), + CLK_LOOKUP(tvclk, "tv", NULL), + CLK_LOOKUP(tvclk, "mcde", "tv"), +}; + +static struct clk_lookup u8500_common_prcc_clocks[] = { + /* PERIPH 1 */ + CLK_LOOKUP(p1_uart0_clk, "uart0", NULL), + CLK_LOOKUP(p1_uart1_clk, "uart1", NULL), + CLK_LOOKUP(p1_i2c1_clk, "nmk-i2c.1", NULL), + CLK_LOOKUP(p1_msp0_clk, "msp0", NULL), + CLK_LOOKUP(p1_msp0_clk, "MSP_I2S.0", NULL), + CLK_LOOKUP(p1_sdi0_clk, "sdi0", NULL), + CLK_LOOKUP(p1_i2c2_clk, "nmk-i2c.2", NULL), + CLK_LOOKUP(p1_slimbus0_clk, "slimbus0", NULL), + CLK_LOOKUP(p1_pclk9, "gpio.0", NULL), + CLK_LOOKUP(p1_pclk9, "gpio.1", NULL), + CLK_LOOKUP(p1_pclk9, "gpioblock0", NULL), + + /* PERIPH 2 */ + CLK_LOOKUP(p2_i2c3_clk, "nmk-i2c.3", NULL), + CLK_LOOKUP(p2_pclk1, "spi2", NULL), + CLK_LOOKUP(p2_pclk2, "spi1", NULL), + CLK_LOOKUP(p2_pclk3, "pwl", NULL), + CLK_LOOKUP(p2_sdi4_clk, "sdi4", NULL), + + /* PERIPH 3 */ + CLK_LOOKUP(p3_pclk0, "fsmc", NULL), + CLK_LOOKUP(p3_i2c0_clk, "nmk-i2c.0", NULL), + CLK_LOOKUP(p3_sdi2_clk, "sdi2", NULL), + CLK_LOOKUP(p3_ske_clk, "ske", NULL), + CLK_LOOKUP(p3_ske_clk, "nmk-ske-keypad", NULL), + CLK_LOOKUP(p3_uart2_clk, "uart2", NULL), + CLK_LOOKUP(p3_sdi5_clk, "sdi5", NULL), + CLK_LOOKUP(p3_pclk8, "gpio.2", NULL), + CLK_LOOKUP(p3_pclk8, "gpio.3", NULL), + CLK_LOOKUP(p3_pclk8, "gpio.4", NULL), + CLK_LOOKUP(p3_pclk8, "gpio.5", NULL), + CLK_LOOKUP(p3_pclk8, "gpioblock2", NULL), + + /* PERIPH 5 */ + CLK_LOOKUP(p5_pclk1, "gpio.8", NULL), + CLK_LOOKUP(p5_pclk1, "gpioblock3", NULL), + + /* PERIPH 6 */ + CLK_LOOKUP(p6_pclk1, "cryp0", NULL), + CLK_LOOKUP(p6_pclk2, "hash0", NULL), + CLK_LOOKUP(p6_pclk3, "pka", NULL), +}; + +static struct clk_lookup u8500_ed_prcc_clocks[] = { + /* PERIPH 1 */ + CLK_LOOKUP(p1_msp1_ed_clk, "msp1", NULL), + CLK_LOOKUP(p1_msp1_ed_clk, "MSP_I2S.1", NULL), + CLK_LOOKUP(p1_pclk7, "spi3", NULL), + + /* PERIPH 2 */ + CLK_LOOKUP(p2_msp2_ed_clk, "msp2", NULL), + CLK_LOOKUP(p2_msp2_ed_clk, "MSP_I2S.2", NULL), + CLK_LOOKUP(p2_sdi1_ed_clk, "sdi1", NULL), + CLK_LOOKUP(p2_sdi3_ed_clk, "sdi3", NULL), + CLK_LOOKUP(p2_pclk9, "spi0", NULL), + CLK_LOOKUP(p2_pclk12, "gpio.6", NULL), + CLK_LOOKUP(p2_pclk12, "gpio.7", NULL), + CLK_LOOKUP(p2_pclk12, "gpioblock1", NULL), + + /* PERIPH 3 */ + CLK_LOOKUP(p3_ssp0_ed_clk, "ssp0", NULL), + CLK_LOOKUP(p3_ssp1_ed_clk, "ssp1", NULL), + + /* PERIPH 5 */ + CLK_LOOKUP(p5_usb_ed_clk, "musb_hdrc.0", "usb"), + + /* PERIPH 6 */ + CLK_LOOKUP(p6_rng_ed_clk, "rng", NULL), + CLK_LOOKUP(p6_pclk4, "cryp1", NULL), + CLK_LOOKUP(p6_pclk5, "hash1", NULL), + CLK_LOOKUP(p6_pclk6, "dmc", NULL), + + /* PERIPH 7 */ + CLK_LOOKUP(p7_pclk0, "cfgreg", NULL), + CLK_LOOKUP(p7_pclk1, "wdg", NULL), + CLK_LOOKUP(p7_mtu0_ed_clk, "mtu0", NULL), + CLK_LOOKUP(p7_mtu1_ed_clk, "mtu1", NULL), + CLK_LOOKUP(p7_pclk4, "tzpc0", NULL), +}; + +static struct clk_lookup u8500_v1_v2_prcmu_clocks[] = { + CLK_LOOKUP(msp1clk, "MSP1", NULL), + CLK_LOOKUP(dsialtclk, "dsialt", NULL), + CLK_LOOKUP(sspclk, "SSP", NULL), + CLK_LOOKUP(rngclk, "rngclk", NULL), + CLK_LOOKUP(uiccclk, "uicc", NULL), +}; + +static struct clk_lookup u8500_v1_v2_prcc_clocks[] = { + /* PERIPH 1 */ + CLK_LOOKUP(p1_msp1_clk, "msp1", NULL), + CLK_LOOKUP(p1_msp1_clk, "MSP_I2S.1", NULL), + CLK_LOOKUP(p1_msp1_kclk, "ab8500-codec.0", "msp1-kernel"), + CLK_LOOKUP(p1_pclk4, "ab8500-codec.0", "msp1-bus"), + CLK_LOOKUP(p1_pclk7, "spi3", NULL), + CLK_LOOKUP(p1_i2c4_clk, "nmk-i2c.4", NULL), + + /* PERIPH 2 */ + CLK_LOOKUP(p2_msp2_clk, "msp2", NULL), + CLK_LOOKUP(p2_msp2_clk, "MSP_I2S.2", NULL), + CLK_LOOKUP(p2_sdi1_clk, "sdi1", NULL), + CLK_LOOKUP(p2_sdi3_clk, "sdi3", NULL), + CLK_LOOKUP(p2_pclk8, "spi0", NULL), + CLK_LOOKUP(p2_pclk9, "ste_hsi.0", "hsir_hclk"), + CLK_LOOKUP(p2_pclk10, "ste_hsi.0", "hsit_hclk"), + CLK_LOOKUP(p2_pclk11, "gpio.6", NULL), + CLK_LOOKUP(p2_pclk11, "gpio.7", NULL), + CLK_LOOKUP(p2_pclk11, "gpioblock1", NULL), + + /* PERIPH 3 */ + CLK_LOOKUP(p3_ssp0_clk, "ssp0", NULL), + CLK_LOOKUP(p3_ssp1_clk, "ssp1", NULL), + + /* PERIPH 5 */ + CLK_LOOKUP(p5_pclk0, "musb_hdrc.0", "usb"), + + /* PERIPH 6 */ + CLK_LOOKUP(p6_pclk5, "hash1", NULL), + CLK_LOOKUP(p6_pclk4, "cryp1", NULL), + CLK_LOOKUP(p6_rng_clk, "rng", NULL), +}; + +static struct clk_lookup u8500_v2_prcmu_clocks[] = { + CLK_LOOKUP(clkout0, "pri-cam", NULL), + CLK_LOOKUP(clkout1, "3-005c", NULL), + CLK_LOOKUP(clkout1, "3-005d", NULL), + CLK_LOOKUP(clkout1, "sec-cam", NULL), +}; + +static struct clk_lookup u8500_v2_prcc_clocks[] = { + /* PERIPH 1 */ + CLK_LOOKUP(p1_msp3_clk, "msp3", NULL), + CLK_LOOKUP(p1_msp3_clk, "MSP_I2S.3", NULL), + CLK_LOOKUP(p1_msp3_kclk, "ab8500-codec.0", "msp3-kernel"), + CLK_LOOKUP(p1_pclk11, "ab8500-codec.0", "msp3-bus"), + + /* PERIPH 6 */ + CLK_LOOKUP(p6_pclk4, "hash1", NULL), + CLK_LOOKUP(p6_pclk4, "cryp1", NULL), + CLK_LOOKUP(p6_pclk5, "cfgreg", NULL), + CLK_LOOKUP(p6_mtu0_clk, "mtu0", NULL), + CLK_LOOKUP(p6_mtu1_clk, "mtu1", NULL), +}; + +/* these are the clocks which are default from the bootloader */ +static const char *u8500_boot_clk[] = { + "uart0", + "uart1", + "uart2", + "gpioblock0", + "gpioblock1", + "gpioblock2", + "gpioblock3", + "mtu0", + "mtu1", + "ssp0", + "ssp1", + "spi0", + "spi1", + "spi2", + "spi3", + "msp0", + "msp2", + "nmk-i2c.0", + "nmk-i2c.1", + "nmk-i2c.2", + "nmk-i2c.3", + "nmk-i2c.4", +}; + +static void sysclk_init_disable(struct work_struct *not_used) +{ + int i; + + mutex_lock(&sysclk_mutex); + + /* Enable SWAT */ + if (ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE)) + goto err_swat; + + for (i = 0; i < ARRAY_SIZE(u8500_v2_sysclks); i++) { + struct clk *clk = u8500_v2_sysclks[i].clk; + + /* Disable sysclks */ + if (!clk->enabled && clk->cg_sel) { + if (ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, + (u8)clk->cg_sel)) + goto err_sysclk; + } + } + goto unlock_and_exit; + +err_sysclk: + pr_err("clock: Disable %s failed", u8500_v2_sysclks[i].clk->name); + ab8500_sysctrl_clear(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE); + goto unlock_and_exit; + +err_swat: + pr_err("clock: Enable SWAT failed"); + +unlock_and_exit: + mutex_unlock(&sysclk_mutex); +} + +struct clk *boot_clks[ARRAY_SIZE(u8500_boot_clk)]; + +/* we disable a majority of peripherals enabled by default + * but without drivers + */ +static int __init u8500_boot_clk_disable(void) +{ + unsigned int i = 0; + + for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) { + if (!boot_clks[i]) + continue; + + clk_disable(boot_clks[i]); + clk_put(boot_clks[i]); + } + + INIT_DELAYED_WORK(&sysclk_disable_work, sysclk_init_disable); + schedule_delayed_work(&sysclk_disable_work, 10 * HZ); + + return 0; +} +late_initcall_sync(u8500_boot_clk_disable); + +static void u8500_amba_clk_enable(void) +{ + unsigned int i = 0; + + writel(~0x0 & ~(1 << 9), __io_address(U8500_PER1_BASE + 0xF000 + + 0x04)); + writel(~0x0, __io_address(U8500_PER1_BASE + 0xF000 + 0x0C)); + + writel(~0x0 & ~(1 << 11), __io_address(U8500_PER2_BASE + 0xF000 + + 0x04)); + writel(~0x0, __io_address(U8500_PER2_BASE + 0xF000 + 0x0C)); + + /*GPIO,UART2 are enabled for booting*/ + writel(0xBF, __io_address(U8500_PER3_BASE + 0xF000 + 0x04)); + writel(~0x0 & ~(1 << 6), __io_address(U8500_PER3_BASE + 0xF000 + + 0x0C)); + + for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) { + boot_clks[i] = clk_get_sys(u8500_boot_clk[i], NULL); + clk_enable(boot_clks[i]); + } +} + +int __init db8500_clk_init(void) +{ + if (cpu_is_u8500ed()) { + pr_err("clock: U8500 ED is no longer supported.\n"); + return -ENOSYS; + } else if (cpu_is_u8500v1()) { + pr_err("clock: U8500 V1 is no longer supported.\n"); + return -ENOSYS; + } else if (cpu_is_u5500()) { + per6clk.rate = 26000000; + uartclk.rate = 36360000; + } + + if (cpu_is_u5500() || ux500_is_svp()) { + sysclk_ops.enable = NULL; + sysclk_ops.disable = NULL; + prcmu_clk_ops.enable = NULL; + prcmu_clk_ops.disable = NULL; + prcmu_opp100_clk_ops.enable = NULL; + prcmu_opp100_clk_ops.disable = NULL; + prcc_pclk_ops.enable = NULL; + prcc_pclk_ops.disable = NULL; + prcc_kclk_ops.enable = NULL; + prcc_kclk_ops.disable = NULL; + clkout0_ops.enable = NULL; + clkout0_ops.disable = NULL; + clkout1_ops.enable = NULL; + clkout1_ops.disable = NULL; + } + + clks_register(u8500_common_clock_sources, + ARRAY_SIZE(u8500_common_clock_sources)); + clks_register(u8500_common_prcmu_clocks, + ARRAY_SIZE(u8500_common_prcmu_clocks)); + clks_register(u8500_common_prcc_clocks, + ARRAY_SIZE(u8500_common_prcc_clocks)); + + if (cpu_is_u5500()) { + clks_register(u8500_ed_prcc_clocks, + ARRAY_SIZE(u8500_ed_prcc_clocks)); + } else if (cpu_is_u8500v2()) { + clks_register(u8500_v2_sysclks, + ARRAY_SIZE(u8500_v2_sysclks)); + clks_register(u8500_v1_v2_prcmu_clocks, + ARRAY_SIZE(u8500_v1_v2_prcmu_clocks)); + clks_register(u8500_v2_prcmu_clocks, + ARRAY_SIZE(u8500_v2_prcmu_clocks)); + clks_register(u8500_v1_v2_prcc_clocks, + ARRAY_SIZE(u8500_v1_v2_prcc_clocks)); + clks_register(u8500_v2_prcc_clocks, + ARRAY_SIZE(u8500_v2_prcc_clocks)); + } + + if (cpu_is_u8500()) + u8500_amba_clk_enable(); + + /* + * The following clks are shared with secure world. + * Currently this leads to a limitation where we need to + * enable them at all times. + */ + clk_enable(&p6_pclk1); + clk_enable(&p6_pclk2); + clk_enable(&p6_pclk3); + if (cpu_is_u8500() && !ux500_is_svp()) + clk_enable(&p6_rng_clk); + + /* + * APEATCLK and APETRACECLK are enabled at boot and needed + * in order to debug with lauterbach + */ + clk_enable(&apeatclk); + clk_enable(&apetraceclk); +#ifdef CONFIG_UX500_DEBUG_NO_LAUTERBACH + clk_disable(&apeatclk); + clk_disable(&apetraceclk); +#endif + /* periph 7's clock is enabled at boot, but should be off */ + clk_enable(&per7clk); + clk_disable(&per7clk); + + /* the hsirx clock is enabled at boot, but should be off */ + clk_enable(&hsirxclk); + clk_disable(&hsirxclk); + + return 0; +} diff --git a/arch/arm/mach-ux500/clock-debug.c b/arch/arm/mach-ux500/clock-debug.c new file mode 100644 index 00000000000..939edfaa94a --- /dev/null +++ b/arch/arm/mach-ux500/clock-debug.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL) version 2 + * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST-Ericsson + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/clk.h> + +#include "clock.h" + +struct clk_debug_info { + struct clk *clk; + struct dentry *dir; + struct dentry *enable; + struct dentry *requests; + int enabled; +}; + +#ifdef CONFIG_DEBUG_FS + +static struct dentry *clk_dir; +static struct dentry *clk_show; +static struct dentry *clk_show_enabled_only; + +static struct clk_debug_info *cdi; +static int num_clks; + +static int clk_show_print(struct seq_file *s, void *p) +{ + int i; + int enabled_only = (int)s->private; + + seq_printf(s, "\n%-20s %s\n", "name", "enabled (kernel + debug)"); + for (i = 0; i < num_clks; i++) { + if (enabled_only && !cdi[i].clk->enabled) + continue; + seq_printf(s, + "%-20s %5d + %d\n", + cdi[i].clk->name, + cdi[i].clk->enabled - cdi[i].enabled, + cdi[i].enabled); + } + + return 0; +} + +static int clk_show_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_show_print, inode->i_private); +} + +static int clk_enable_print(struct seq_file *s, void *p) +{ + struct clk_debug_info *cdi = s->private; + + return seq_printf(s, "%d\n", cdi->enabled); +} + +static int clk_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_enable_print, inode->i_private); +} + +static ssize_t clk_enable_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct clk_debug_info *cdi; + char buf[32]; + ssize_t buf_size; + long user_val; + int err; + + cdi = ((struct seq_file *)(file->private_data))->private; + + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = '\0'; + + err = strict_strtol(buf, 0, &user_val); + if (err) + return -EINVAL; + if ((user_val > 0) && (!cdi->enabled)) { + err = clk_enable(cdi->clk); + if (err) { + pr_err("clock: clk_enable(%s) failed.\n", + cdi->clk->name); + return -EFAULT; + } + cdi->enabled = 1; + } else if ((user_val <= 0) && (cdi->enabled)) { + clk_disable(cdi->clk); + cdi->enabled = 0; + } + return buf_size; +} + +static int clk_requests_print(struct seq_file *s, void *p) +{ + struct clk_debug_info *cdi = s->private; + + return seq_printf(s, "%d\n", cdi->clk->enabled); +} + +static int clk_requests_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_requests_print, inode->i_private); +} + +static const struct file_operations clk_enable_fops = { + .open = clk_enable_open, + .write = clk_enable_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations clk_requests_fops = { + .open = clk_requests_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations clk_show_fops = { + .open = clk_show_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int create_clk_dirs(struct clk_debug_info *cdi, int size) +{ + int i; + + for (i = 0; i < size; i++) { + cdi[i].dir = debugfs_create_dir(cdi[i].clk->name, clk_dir); + if (!cdi[i].dir) + goto no_dir; + } + + for (i = 0; i < size; i++) { + cdi[i].enable = debugfs_create_file("enable", + (S_IRUGO | S_IWUGO), + cdi[i].dir, &cdi[i], + &clk_enable_fops); + if (!cdi[i].enable) + goto no_enable; + } + for (i = 0; i < size; i++) { + cdi[i].requests = debugfs_create_file("requests", S_IRUGO, + cdi[i].dir, &cdi[i], + &clk_requests_fops); + if (!cdi[i].requests) + goto no_requests; + } + return 0; + +no_requests: + while (i--) + debugfs_remove(cdi[i].requests); + i = size; +no_enable: + while (i--) + debugfs_remove(cdi[i].enable); + i = size; +no_dir: + while (i--) + debugfs_remove(cdi[i].dir); + + return -ENOMEM; +} + +int __init dbx500_clk_debug_init(struct clk **clks, int num) +{ + int i; + + cdi = kcalloc(sizeof(struct clk_debug_info), num, GFP_KERNEL); + if (!cdi) + return -ENOMEM; + + for (i = 0; i < num; i++) + cdi[i].clk = clks[i]; + + num_clks = num; + + clk_dir = debugfs_create_dir("clk", NULL); + if (!clk_dir) + goto no_dir; + + clk_show = debugfs_create_file("show", S_IRUGO, clk_dir, (void *)0, + &clk_show_fops); + if (!clk_show) + goto no_show; + + clk_show_enabled_only = debugfs_create_file("show-enabled-only", + S_IRUGO, clk_dir, (void *)1, + &clk_show_fops); + if (!clk_show_enabled_only) + goto no_enabled_only; + + if (create_clk_dirs(cdi, num)) + goto no_clks; + + return 0; + +no_clks: + debugfs_remove(clk_show_enabled_only); +no_enabled_only: + debugfs_remove(clk_show); +no_show: + debugfs_remove(clk_dir); +no_dir: + kfree(cdi); + return -ENOMEM; +} + +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 0a1318fc8e2..85cbae721bb 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -7,611 +7,380 @@ * published by the Free Software Foundation. */ #include <linux/module.h> -#include <linux/kernel.h> -#include <linux/list.h> #include <linux/errno.h> -#include <linux/err.h> -#include <linux/clk.h> #include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/mfd/ab8500/sysctrl.h> +#include <mach/prcmu-fw-api.h> -#include <asm/clkdev.h> - -#include <plat/mtu.h> -#include <mach/hardware.h> #include "clock.h" -#define PRCC_PCKEN 0x00 -#define PRCC_PCKDIS 0x04 -#define PRCC_KCKEN 0x08 -#define PRCC_KCKDIS 0x0C - -#define PRCM_YYCLKEN0_MGT_SET 0x510 -#define PRCM_YYCLKEN1_MGT_SET 0x514 -#define PRCM_YYCLKEN0_MGT_CLR 0x518 -#define PRCM_YYCLKEN1_MGT_CLR 0x51C -#define PRCM_YYCLKEN0_MGT_VAL 0x520 -#define PRCM_YYCLKEN1_MGT_VAL 0x524 - -#define PRCM_SVAMMDSPCLK_MGT 0x008 -#define PRCM_SIAMMDSPCLK_MGT 0x00C -#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_TCR 0x1C8 -#define PRCM_TCR_STOPPED (1 << 16) -#define PRCM_TCR_DOZE_MODE (1 << 17) -#define PRCM_UNIPROCLK_MGT 0x278 -#define PRCM_SSPCLK_MGT 0x280 -#define PRCM_RNGCLK_MGT 0x284 -#define PRCM_UICCCLK_MGT 0x27C - -#define PRCM_MGT_ENABLE (1 << 8) - -static DEFINE_SPINLOCK(clocks_lock); - -static void __clk_enable(struct clk *clk) -{ - if (clk->enabled++ == 0) { - if (clk->parent_cluster) - __clk_enable(clk->parent_cluster); +#define PRCC_PCKEN 0x0 +#define PRCC_PCKDIS 0x4 +#define PRCC_KCKEN 0x8 +#define PRCC_KCKDIS 0xC +#define PRCC_PCKSR 0x10 +#define PRCC_KCKSR 0x14 - if (clk->parent_periph) - __clk_enable(clk->parent_periph); +DEFINE_MUTEX(clk_opp100_mutex); +static DEFINE_SPINLOCK(clk_spin_lock); +#define NO_LOCK &clk_spin_lock - if (clk->ops && clk->ops->enable) - clk->ops->enable(clk); +static void __iomem *prcmu_base; + +static void __clk_lock(struct clk *clk, void *last_lock, unsigned long *flags) +{ + if (clk->mutex != last_lock) { + if (clk->mutex == NULL) + spin_lock_irqsave(&clk_spin_lock, *flags); + else + mutex_lock(clk->mutex); } } -int clk_enable(struct clk *clk) +static void __clk_unlock(struct clk *clk, void *last_lock, unsigned long flags) +{ + if (clk->mutex != last_lock) { + if (clk->mutex == NULL) + spin_unlock_irqrestore(&clk_spin_lock, flags); + else + mutex_unlock(clk->mutex); + } +} + +static void __clk_disable(struct clk *clk, void *current_lock) { unsigned long flags; - spin_lock_irqsave(&clocks_lock, flags); - __clk_enable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); + if (clk == NULL) + return; - return 0; -} -EXPORT_SYMBOL(clk_enable); + __clk_lock(clk, current_lock, &flags); -static void __clk_disable(struct clk *clk) -{ - if (--clk->enabled == 0) { - if (clk->ops && clk->ops->disable) + if (clk->enabled && (--clk->enabled == 0)) { + if ((clk->ops != NULL) && (clk->ops->disable != NULL)) clk->ops->disable(clk); + __clk_disable(clk->parent, clk->mutex); + __clk_disable(clk->bus_parent, clk->mutex); + } - if (clk->parent_periph) - __clk_disable(clk->parent_periph); + __clk_unlock(clk, current_lock, flags); - if (clk->parent_cluster) - __clk_disable(clk->parent_cluster); - } + return; } -void clk_disable(struct clk *clk) +static int __clk_enable(struct clk *clk, void *current_lock) { + int err; unsigned long flags; - WARN_ON(!clk->enabled); + if (clk == NULL) + return 0; - spin_lock_irqsave(&clocks_lock, flags); - __clk_disable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); + __clk_lock(clk, current_lock, &flags); -/* - * The MTU has a separate, rather complex muxing setup - * with alternative parents (peripheral cluster or - * ULP or fixed 32768 Hz) depending on settings - */ -static unsigned long clk_mtu_get_rate(struct clk *clk) -{ - void __iomem *addr = __io_address(UX500_PRCMU_BASE) - + PRCM_TCR; - u32 tcr = readl(addr); - int mtu = (int) clk->data; - /* - * One of these is selected eventually - * TODO: Replace the constant with a reference - * to the ULP source once this is modeled. - */ - unsigned long clk32k = 32768; - unsigned long mturate; - unsigned long retclk; - - /* Get the rate from the parent as a default */ - if (clk->parent_periph) - mturate = clk_get_rate(clk->parent_periph); - else if (clk->parent_cluster) - mturate = clk_get_rate(clk->parent_cluster); - else - /* We need to be connected SOMEWHERE */ - BUG(); - - /* - * Are we in doze mode? - * In this mode the parent peripheral or the fixed 32768 Hz - * clock is fed into the block. - */ - if (!(tcr & PRCM_TCR_DOZE_MODE)) { - /* - * Here we're using the clock input from the APE ULP - * clock domain. But first: are the timers stopped? - */ - if (tcr & PRCM_TCR_STOPPED) { - clk32k = 0; - mturate = 0; - } else { - /* Else default mode: 0 and 2.4 MHz */ - clk32k = 0; - if (cpu_is_u5500()) - /* DB5500 divides by 8 */ - mturate /= 8; - else if (cpu_is_u8500ed()) { - /* - * This clocking setting must not be used - * in the ED chip, it is simply not - * connected anywhere! - */ - mturate = 0; - BUG(); - } else - /* - * In this mode the ulp38m4 clock is divided - * by a factor 16, on the DB8500 typically - * 38400000 / 16 ~ 2.4 MHz. - * TODO: Replace the constant with a reference - * to the ULP source once this is modeled. - */ - mturate = 38400000 / 16; + if (!clk->enabled) { + err = __clk_enable(clk->bus_parent, clk->mutex); + if (unlikely(err)) + goto bus_parent_error; + + err = __clk_enable(clk->parent, clk->mutex); + if (unlikely(err)) + goto parent_error; + + if ((clk->ops != NULL) && (clk->ops->enable != NULL)) { + err = clk->ops->enable(clk); + if (unlikely(err)) + goto enable_error; } } + clk->enabled++; - /* Return the clock selected for this MTU */ - if (tcr & (1 << mtu)) - retclk = clk32k; - else - retclk = mturate; + __clk_unlock(clk, current_lock, flags); + + return 0; + +enable_error: + __clk_disable(clk->parent, clk->mutex); +parent_error: + __clk_disable(clk->bus_parent, clk->mutex); +bus_parent_error: - pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk); - return retclk; + __clk_unlock(clk, current_lock, flags); + + return err; } -unsigned long clk_get_rate(struct clk *clk) +unsigned long __clk_get_rate(struct clk *clk, void *current_lock) { unsigned long rate; + unsigned long flags; - /* - * If there is a custom getrate callback for this clock, - * it will take precedence. - */ - if (clk->get_rate) - return clk->get_rate(clk); - - if (clk->ops && clk->ops->get_rate) - return clk->ops->get_rate(clk); - - rate = clk->rate; - if (!rate) { - if (clk->parent_periph) - rate = clk_get_rate(clk->parent_periph); - else if (clk->parent_cluster) - rate = clk_get_rate(clk->parent_cluster); - } + if (clk == NULL) + return 0; + + __clk_lock(clk, current_lock, &flags); + + if ((clk->ops != NULL) && (clk->ops->get_rate != NULL)) + rate = clk->ops->get_rate(clk); + else if (clk->rate) + rate = clk->rate; + else + rate = __clk_get_rate(clk->parent, clk->mutex); + + __clk_unlock(clk, current_lock, flags); return rate; } + +static unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) +{ + if ((clk->ops != NULL) && (clk->ops->round_rate != NULL)) + return clk->ops->round_rate(clk, rate); + + return -ENOSYS; +} + +static int __clk_set_rate(struct clk *clk, unsigned long rate) +{ + if ((clk->ops != NULL) && (clk->ops->set_rate != NULL)) + return clk->ops->set_rate(clk, rate); + + return -ENOSYS; +} + +int clk_enable(struct clk *clk) +{ + if (clk == NULL) + return -EINVAL; + + return __clk_enable(clk, NO_LOCK); +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + + if (clk == NULL) + return; + + WARN_ON(!clk->enabled); + __clk_disable(clk, NO_LOCK); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk == NULL) + return 0; + + return __clk_get_rate(clk, NO_LOCK); +} EXPORT_SYMBOL(clk_get_rate); long clk_round_rate(struct clk *clk, unsigned long rate) { - /*TODO*/ + unsigned long flags; + + if (clk == NULL) + return -EINVAL; + + __clk_lock(clk, NO_LOCK, &flags); + + rate = __clk_round_rate(clk, rate); + + __clk_unlock(clk, NO_LOCK, flags); + return rate; } EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { - clk->rate = rate; - return 0; + int err; + unsigned long flags; + + if (clk == NULL) + return -EINVAL; + + __clk_lock(clk, NO_LOCK, &flags); + + err = __clk_set_rate(clk, rate); + + __clk_unlock(clk, NO_LOCK, flags); + + return err; } EXPORT_SYMBOL(clk_set_rate); -static void clk_prcmu_enable(struct clk *clk) +int clk_set_parent(struct clk *clk, struct clk *parent) { - void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE) - + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off; + int err = 0; + unsigned long flags; + struct clk **p; + + if ((clk == NULL) || (clk->parents == NULL)) + return -EINVAL; + for (p = clk->parents; *p != parent; p++) { + if (*p == NULL) /* invalid parent */ + return -EINVAL; + } + + __clk_lock(clk, NO_LOCK, &flags); + + if ((clk->ops != NULL) && (clk->ops->set_parent != NULL)) { + err = clk->ops->set_parent(clk, parent); + if (err) + goto unlock_and_return; + } else if (clk->enabled) { + err = __clk_enable(parent, clk->mutex); + if (err) + goto unlock_and_return; + __clk_disable(clk->parent, clk->mutex); + } + + clk->parent = parent; - writel(1 << clk->prcmu_cg_bit, cg_set_reg); +unlock_and_return: + __clk_unlock(clk, NO_LOCK, flags); + + return err; } -static void clk_prcmu_disable(struct clk *clk) -{ - void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE) - + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off; +/* PRCMU clock operations. */ - writel(1 << clk->prcmu_cg_bit, cg_clr_reg); +static int prcmu_clk_enable(struct clk *clk) +{ + return prcmu_request_clock(clk->cg_sel, true); } -/* ED doesn't have the combined set/clr registers */ -static void clk_prcmu_ed_enable(struct clk *clk) +static void prcmu_clk_disable(struct clk *clk) { - void __iomem *addr = __io_address(U8500_PRCMU_BASE) - + clk->prcmu_cg_mgt; + if (prcmu_request_clock(clk->cg_sel, false)) { + pr_err("clock: %s failed to disable %s.\n", __func__, + clk->name); + } +} - writel(readl(addr) | PRCM_MGT_ENABLE, addr); +static int request_ape_opp100(bool enable) +{ + static unsigned int requests; + + if (enable) { + if (0 == requests++) { + return prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + "clock", 100); + } + } else if (1 == requests--) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "clock"); + } + return 0; } -static void clk_prcmu_ed_disable(struct clk *clk) +static int prcmu_opp100_clk_enable(struct clk *clk) { - void __iomem *addr = __io_address(U8500_PRCMU_BASE) - + clk->prcmu_cg_mgt; + int r; + + r = request_ape_opp100(true); + if (r) { + pr_err("clock: %s failed to request APE OPP 100%% for %s.\n", + __func__, clk->name); + return r; + } + return prcmu_request_clock(clk->cg_sel, true); +} - writel(readl(addr) & ~PRCM_MGT_ENABLE, addr); +static void prcmu_opp100_clk_disable(struct clk *clk) +{ + if (prcmu_request_clock(clk->cg_sel, false)) + goto out_error; + if (request_ape_opp100(false)) + goto out_error; + return; + +out_error: + pr_err("clock: %s failed to disable %s.\n", __func__, clk->name); } -static struct clkops clk_prcmu_ops = { - .enable = clk_prcmu_enable, - .disable = clk_prcmu_disable, +struct clkops prcmu_clk_ops = { + .enable = prcmu_clk_enable, + .disable = prcmu_clk_disable, }; -static unsigned int clkrst_base[] = { - [1] = U8500_CLKRST1_BASE, - [2] = U8500_CLKRST2_BASE, - [3] = U8500_CLKRST3_BASE, - [5] = U8500_CLKRST5_BASE, - [6] = U8500_CLKRST6_BASE, - [7] = U8500_CLKRST7_BASE_ED, +struct clkops prcmu_opp100_clk_ops = { + .enable = prcmu_opp100_clk_enable, + .disable = prcmu_opp100_clk_disable, }; -static void clk_prcc_enable(struct clk *clk) -{ - void __iomem *addr = __io_address(clkrst_base[clk->cluster]); +/* PRCC clock operations. */ - if (clk->prcc_kernel != -1) - writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN); +static int prcc_pclk_enable(struct clk *clk) +{ + void __iomem *io_base = __io_address(clk->io_base); - if (clk->prcc_bus != -1) - writel(1 << clk->prcc_bus, addr + PRCC_PCKEN); + writel(clk->cg_sel, (io_base + PRCC_PCKEN)); + while (!(readl(io_base + PRCC_PCKSR) & clk->cg_sel)) + cpu_relax(); + return 0; } -static void clk_prcc_disable(struct clk *clk) +static void prcc_pclk_disable(struct clk *clk) { - void __iomem *addr = __io_address(clkrst_base[clk->cluster]); - - if (clk->prcc_bus != -1) - writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS); + void __iomem *io_base = __io_address(clk->io_base); - if (clk->prcc_kernel != -1) - writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS); + writel(clk->cg_sel, (io_base + PRCC_PCKDIS)); } -static struct clkops clk_prcc_ops = { - .enable = clk_prcc_enable, - .disable = clk_prcc_disable, +struct clkops prcc_pclk_ops = { + .enable = prcc_pclk_enable, + .disable = prcc_pclk_disable, }; -static struct clk clk_32khz = { - .rate = 32000, -}; +static int prcc_kclk_enable(struct clk *clk) +{ + void __iomem *io_base = __io_address(clk->io_base); -/* - * PRCMU level clock gating - */ + writel(clk->cg_sel, (io_base + PRCC_KCKEN)); + while (!(readl(io_base + PRCC_KCKSR) & clk->cg_sel)) + cpu_relax(); + return 0; +} -/* Bank 0 */ -static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK); -static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK); -static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK); -static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000); -static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK); -static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */ -static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000); -static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000); -static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK); -static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK); -static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK); -static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK); -static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK); -static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000); -static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000); -static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK); -static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK); -static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK); -static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK); -static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK); -static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK); -static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK); -static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK); -static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK); -static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */ -static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK); -static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK); -static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK); -static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */ -static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */ - -/* Bank 1 */ -static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */ -static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */ +static void prcc_kclk_disable(struct clk *clk) +{ + void __iomem *io_base = __io_address(clk->io_base); -/* - * PRCC level clock gating - * Format: per#, clk, PCKEN bit, KCKEN bit, parent - */ + writel(clk->cg_sel, (io_base + PRCC_KCKDIS)); +} -/* Peripheral Cluster #1 */ -static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); -static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); -static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); -static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); -static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); -static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); -static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); -static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); - -/* Peripheral Cluster #2 */ - -static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL); -static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); -static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); -static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); -static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); -static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL); -static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); -static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); -static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); - -static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL); -static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); -static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); -static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); -static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL); -static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); -static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); -static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); - -/* Peripheral Cluster #3 */ -static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); -static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); -static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); -static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); -static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); -static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); - -/* Peripheral Cluster #4 is in the always on domain */ - -/* Peripheral Cluster #5 */ -static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); -static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); -static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); - -/* Peripheral Cluster #6 */ - -/* MTU ID in data */ -static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); -static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); -static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); -static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); -static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); -static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); -static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); -static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); -static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); -static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); -static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); -static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); - -/* Peripheral Cluster #7 */ - -static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); -/* MTU ID in data */ -static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); -static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); -static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); -static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); - -static struct clk_lookup u8500_common_clks[] = { - /* Peripheral Cluster #1 */ - CLK(gpio0, "gpio.0", NULL), - CLK(gpio0, "gpio.1", NULL), - CLK(slimbus0, "slimbus0", NULL), - CLK(i2c2, "nmk-i2c.2", NULL), - CLK(sdi0, "sdi0", NULL), - CLK(msp0, "msp0", NULL), - CLK(i2c1, "nmk-i2c.1", NULL), - CLK(uart1, "uart1", NULL), - CLK(uart0, "uart0", NULL), - - /* Peripheral Cluster #3 */ - CLK(gpio2, "gpio.2", NULL), - CLK(gpio2, "gpio.3", NULL), - CLK(gpio2, "gpio.4", NULL), - CLK(gpio2, "gpio.5", NULL), - CLK(sdi5, "sdi5", NULL), - CLK(uart2, "uart2", NULL), - CLK(ske, "ske", NULL), - CLK(sdi2, "sdi2", NULL), - CLK(i2c0, "nmk-i2c.0", NULL), - CLK(fsmc, "fsmc", NULL), - - /* Peripheral Cluster #5 */ - CLK(gpio3, "gpio.8", NULL), - - /* Peripheral Cluster #6 */ - CLK(hash1, "hash1", NULL), - CLK(pka, "pka", NULL), - CLK(hash0, "hash0", NULL), - CLK(cryp0, "cryp0", NULL), - - /* PRCMU level clock gating */ - - /* Bank 0 */ - CLK(svaclk, "sva", NULL), - CLK(siaclk, "sia", NULL), - CLK(sgaclk, "sga", NULL), - CLK(slimclk, "slim", NULL), - CLK(lcdclk, "lcd", NULL), - CLK(bmlclk, "bml", NULL), - CLK(hsitxclk, "stm-hsi.0", NULL), - CLK(hsirxclk, "stm-hsi.1", NULL), - CLK(hdmiclk, "hdmi", NULL), - CLK(apeatclk, "apeat", NULL), - CLK(apetraceclk, "apetrace", NULL), - CLK(mcdeclk, "mcde", NULL), - CLK(ipi2clk, "ipi2", NULL), - CLK(dmaclk, "dma40.0", NULL), - CLK(b2r2clk, "b2r2", NULL), - CLK(tvclk, "tv", NULL), +struct clkops prcc_kclk_ops = { + .enable = prcc_kclk_enable, + .disable = prcc_kclk_disable, }; -static struct clk_lookup u8500_ed_clks[] = { - /* Peripheral Cluster #1 */ - CLK(spi3_ed, "spi3", NULL), - CLK(msp1_ed, "msp1", NULL), - - /* Peripheral Cluster #2 */ - CLK(gpio1_ed, "gpio.6", NULL), - CLK(gpio1_ed, "gpio.7", NULL), - CLK(ssitx_ed, "ssitx", NULL), - CLK(ssirx_ed, "ssirx", NULL), - CLK(spi0_ed, "spi0", NULL), - CLK(sdi3_ed, "sdi3", NULL), - CLK(sdi1_ed, "sdi1", NULL), - CLK(msp2_ed, "msp2", NULL), - CLK(sdi4_ed, "sdi4", NULL), - CLK(pwl_ed, "pwl", NULL), - CLK(spi1_ed, "spi1", NULL), - CLK(spi2_ed, "spi2", NULL), - CLK(i2c3_ed, "nmk-i2c.3", NULL), - - /* Peripheral Cluster #3 */ - CLK(ssp1_ed, "ssp1", NULL), - CLK(ssp0_ed, "ssp0", NULL), - - /* Peripheral Cluster #5 */ - CLK(usb_ed, "musb_hdrc.0", "usb"), - - /* Peripheral Cluster #6 */ - CLK(dmc_ed, "dmc", NULL), - CLK(cryp1_ed, "cryp1", NULL), - CLK(rng_ed, "rng", NULL), - - /* Peripheral Cluster #7 */ - CLK(tzpc0_ed, "tzpc0", NULL), - CLK(mtu1_ed, "mtu1", NULL), - CLK(mtu0_ed, "mtu0", NULL), - CLK(wdg_ed, "wdg", NULL), - CLK(cfgreg_ed, "cfgreg", NULL), -}; +void clks_register(struct clk_lookup *clks, size_t num) +{ + unsigned int i; -static struct clk_lookup u8500_v1_clks[] = { - /* Peripheral Cluster #1 */ - CLK(i2c4, "nmk-i2c.4", NULL), - CLK(spi3_v1, "spi3", NULL), - CLK(msp1_v1, "msp1", NULL), - - /* Peripheral Cluster #2 */ - CLK(gpio1_v1, "gpio.6", NULL), - CLK(gpio1_v1, "gpio.7", NULL), - CLK(ssitx_v1, "ssitx", NULL), - CLK(ssirx_v1, "ssirx", NULL), - CLK(spi0_v1, "spi0", NULL), - CLK(sdi3_v1, "sdi3", NULL), - CLK(sdi1_v1, "sdi1", NULL), - CLK(msp2_v1, "msp2", NULL), - CLK(sdi4_v1, "sdi4", NULL), - CLK(pwl_v1, "pwl", NULL), - CLK(spi1_v1, "spi1", NULL), - CLK(spi2_v1, "spi2", NULL), - CLK(i2c3_v1, "nmk-i2c.3", NULL), - - /* Peripheral Cluster #3 */ - CLK(ssp1_v1, "ssp1", NULL), - CLK(ssp0_v1, "ssp0", NULL), - - /* Peripheral Cluster #5 */ - CLK(usb_v1, "musb_hdrc.0", "usb"), - - /* Peripheral Cluster #6 */ - CLK(mtu1_v1, "mtu1", NULL), - CLK(mtu0_v1, "mtu0", NULL), - CLK(cfgreg_v1, "cfgreg", NULL), - CLK(hash1, "hash1", NULL), - CLK(unipro_v1, "unipro", NULL), - CLK(rng_v1, "rng", NULL), - - /* PRCMU level clock gating */ - - /* Bank 0 */ - CLK(uniproclk, "uniproclk", NULL), - CLK(dsialtclk, "dsialt", NULL), - - /* Bank 1 */ - CLK(rngclk, "rng", NULL), - CLK(uiccclk, "uicc", NULL), -}; + for (i = 0; i < num; i++) + clkdev_add(&clks[i]); +} int __init clk_init(void) { - if (cpu_is_u8500ed()) { - clk_prcmu_ops.enable = clk_prcmu_ed_enable; - clk_prcmu_ops.disable = clk_prcmu_ed_disable; - clk_per6clk.rate = 100000000; + if (cpu_is_u8500()) { + prcmu_base = __io_address(U8500_PRCMU_BASE); } else if (cpu_is_u5500()) { - /* Clock tree for U5500 not implemented yet */ - clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; - clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; - clk_per6clk.rate = 26000000; + prcmu_base = __io_address(U5500_PRCMU_BASE); + } else { + pr_err("clock: Unknown DB Asic.\n"); + return -EIO; } - clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); - if (cpu_is_u8500ed()) - clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks)); - else - clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); + if (cpu_is_u8500()) + db8500_clk_init(); + else if (cpu_is_u5500()) + db5500_clk_init(); return 0; } diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index a0580250152..c242840e784 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h @@ -1,11 +1,53 @@ /* - * Copyright (C) 2010 ST-Ericsson + * Copyright (C) 2010 ST-Ericsson SA * Copyright (C) 2009 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#ifndef UX500_CLOCK_H +#define UX500_CLOCK_H + +#include <asm/clkdev.h> + +/** + * struct clk + * @ops: The hardware specific operations defined for the clock. + * @name: The name of the clock. + * @mutex: The mutex to lock when operating on the clock. %NULL means that + * the common clock spinlock will be used. + * @enabled: A reference counter of the enable requests for the clock. + * @opp100: A flag saying whether the clock is requested to run at the + * OPP 100%% frequency. + * @rate: The frequency of the clock. For scalable and scaling clocks, + * this is the OPP 100%% frequency. + * @io_base: An IO memory base address, meaningful only when considered + * together with the defined @ops. + * @cg_sel: Clock gate selector, meaningful only when considered together + * with the specified @ops. + * @parent: The current (or only) parent clock of the clock. + * @bus_parent: The (optional) auxiliary bus clock "parent" of the clock. + * @parents: A list of the possible parents the clock can have. This should + * be a %NULL-terminated &struct_clk array. Present if and only + * if clk_set_parent() is implemented for the clock. + * @regulator: The regulator needed to have the clock functional, if any. + */ +struct clk { + const struct clkops *ops; + const char *name; + struct mutex *mutex; + unsigned int enabled; + bool opp100; + unsigned long rate; + unsigned int io_base; + u32 cg_sel; + struct clk *parent; + struct clk *bus_parent; + struct clk **parents; + struct regulator *regulator; + struct list_head list; +}; /** * struct clkops - ux500 clock operations @@ -18,130 +60,90 @@ * NULL, the rate in the struct clk will be used. */ struct clkops { - void (*enable) (struct clk *); - void (*disable) (struct clk *); - unsigned long (*get_rate) (struct clk *); + int (*enable)(struct clk *); + void (*disable)(struct clk *); + unsigned long (*get_rate)(struct clk *); + int (*set_rate)(struct clk *, unsigned long); + unsigned long (*round_rate)(struct clk *, unsigned long); + int (*set_parent)(struct clk *, struct clk *); }; -/** - * struct clk - ux500 clock structure - * @ops: pointer to clkops struct used to control this clock - * @name: name, for debugging - * @enabled: refcount. positive if enabled, zero if disabled - * @get_rate: custom callback for getting the clock rate - * @data: custom per-clock data for example for the get_rate - * callback - * @rate: fixed rate for clocks which don't implement - * ops->getrate - * @prcmu_cg_off: address offset of the combined enable/disable register - * (used on u8500v1) - * @prcmu_cg_bit: bit in the combined enable/disable register (used on - * u8500v1) - * @prcmu_cg_mgt: address of the enable/disable register (used on - * u8500ed) - * @cluster: peripheral cluster number - * @prcc_bus: bit for the bus clock in the peripheral's CLKRST - * @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST. - * -1 if no kernel clock exists. - * @parent_cluster: pointer to parent's cluster clk struct - * @parent_periph: pointer to parent's peripheral clk struct - * - * Peripherals are organised into clusters, and each cluster has an associated - * bus clock. Some peripherals also have a parent peripheral clock. - * - * In order to enable a clock for a peripheral, we need to enable: - * (1) the parent cluster (bus) clock at the PRCMU level - * (2) the parent peripheral clock (if any) at the PRCMU level - * (3) the peripheral's bus & kernel clock at the PRCC level - * - * (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each - * of the cluster and peripheral clocks, and hooking these as the parents of - * the individual peripheral clocks. - * - * (3) is handled by specifying the bits in the PRCC control registers required - * to enable these clocks and modifying them in the ->enable and - * ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK). - * - * This structure describes both the PRCMU-level clocks and PRCC-level clocks. - * The prcmu_* fields are only used for the PRCMU clocks, and the cluster, - * prcc, and parent pointers are only used for the PRCC-level clocks. - */ -struct clk { - const struct clkops *ops; - const char *name; - unsigned int enabled; - unsigned long (*get_rate)(struct clk *); - void *data; - - unsigned long rate; - struct list_head list; - - /* These three are only for PRCMU clks */ - - unsigned int prcmu_cg_off; - unsigned int prcmu_cg_bit; - unsigned int prcmu_cg_mgt; +extern struct clkops prcmu_clk_ops; +extern struct clkops prcmu_opp100_clk_ops; +extern struct mutex clk_opp100_mutex; +extern struct clkops prcc_pclk_ops; +extern struct clkops prcc_kclk_ops; +extern struct clkops sga_clk_ops; - /* The rest are only for PRCC clks */ - - int cluster; - unsigned int prcc_bus; - unsigned int prcc_kernel; - - struct clk *parent_cluster; - struct clk *parent_periph; -}; - -#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcmu_ops, \ - .prcmu_cg_off = _cg_off, \ - .prcmu_cg_bit = _cg_bit, \ - .prcmu_cg_mgt = PRCM_##_reg##_MGT \ +/* Define PRCMU Clock */ +#define DEF_PRCMU_CLK(_name, _cg_sel, _rate) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &prcmu_clk_ops, \ + .cg_sel = _cg_sel, \ + .rate = _rate, \ } -#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcmu_ops, \ - .prcmu_cg_off = _cg_off, \ - .prcmu_cg_bit = _cg_bit, \ - .rate = _rate, \ - .prcmu_cg_mgt = PRCM_##_reg##_MGT \ +/* Use this for clocks that are only defined at OPP 100%. */ +#define DEF_PRCMU_OPP100_CLK(_name, _cg_sel, _rate) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &prcmu_opp100_clk_ops, \ + .cg_sel = _cg_sel, \ + .rate = _rate, \ + .mutex = &clk_opp100_mutex, \ } -#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcc_ops, \ - .cluster = _pclust, \ - .prcc_bus = _bus_en, \ - .prcc_kernel = _kernel_en, \ - .parent_cluster = &clk_per##_pclust##clk, \ - .parent_periph = _kernclk \ +/* Define PRCC clock */ +#define DEF_PRCC_PCLK(_name, _io_base, _cg_bit, _parent) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &prcc_pclk_ops, \ + .io_base = _io_base, \ + .cg_sel = BIT(_cg_bit), \ + .parent = _parent, \ } -#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcc_ops, \ - .cluster = _pclust, \ - .prcc_bus = _bus_en, \ - .prcc_kernel = _kernel_en, \ - .parent_cluster = &clk_per##_pclust##clk, \ - .parent_periph = _kernclk, \ - .get_rate = _callback, \ - .data = (void *) _data \ +#define DEF_PRCC_KCLK(_name, _io_base, _cg_bit, _parent) \ + struct clk _name = { \ + .name = #_name, \ + .ops = &prcc_kclk_ops, \ + .io_base = _io_base, \ + .cg_sel = BIT(_cg_bit), \ + .parent = _parent, \ } - -#define CLK(_clk, _devname, _conname) \ - { \ - .clk = &clk_##_clk, \ - .dev_id = _devname, \ - .con_id = _conname, \ +#define DEF_PER_CLK(_name, _bus_parent, _parent) \ + struct clk _name = { \ + .name = #_name, \ + .parent = _parent, \ + .bus_parent = _bus_parent, \ } -int __init clk_db8500_ed_fixup(void); +/* Functions defined in clock.c */ int __init clk_init(void); +void clks_register(struct clk_lookup *clks, size_t num); +unsigned long __clk_get_rate(struct clk *clk, void *current_lock); + +#ifdef CONFIG_DEBUG_FS +int dbx500_clk_debug_init(struct clk **clks, int num); +#else +static inline int dbx500_clk_debug_init(struct clk **clks, int num) +{ + return 0; +} +#endif + +#ifdef CONFIG_UX500_SOC_DB8500 +int __init db8500_clk_init(void); +#else +static inline int db8500_clk_init(void) { return 0; } +#endif + +#ifdef CONFIG_UX500_SOC_DB5500 +int __init db5500_clk_init(void); +#else +static inline int db5500_clk_init(void) { return 0; } +#endif + +#endif diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c index e9278f6d67a..e94282808ec 100644 --- a/arch/arm/mach-ux500/cpu-db5500.c +++ b/arch/arm/mach-ux500/cpu-db5500.c @@ -8,20 +8,127 @@ #include <linux/platform_device.h> #include <linux/amba/bus.h> #include <linux/io.h> +#include <linux/err.h> #include <asm/mach/map.h> #include <mach/hardware.h> #include <mach/devices.h> #include <mach/setup.h> +#include <mach/irqs.h> + +#include "devices-db5500.h" static struct map_desc u5500_io_desc[] __initdata = { + __IO_DEV_DESC(U5500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U5500_MTU1_BASE, SZ_4K), + __IO_DEV_DESC(U5500_SCU_BASE, SZ_4K), + __IO_DEV_DESC(U5500_TWD_BASE, SZ_4K), + __IO_DEV_DESC(U5500_UART0_BASE, SZ_4K), + __IO_DEV_DESC(U5500_UART1_BASE, SZ_4K), + __IO_DEV_DESC(U5500_UART2_BASE, SZ_4K), + __IO_DEV_DESC(U5500_RTC_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO3_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO4_BASE, SZ_4K), __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K), + __IO_DEV_DESC(U5500_PRCMU_TCDM_BASE, SZ_4K), + __MEM_DEV_DESC(U5500_BOOT_ROM_BASE, SZ_1M), + __IO_DEV_DESC(U5500_BACKUPRAM0_BASE, SZ_8K), + __IO_DEV_DESC(U5500_GIC_CPU_BASE, SZ_4K), + __IO_DEV_DESC(U5500_GIC_DIST_BASE, SZ_4K), + __IO_DEV_DESC(U5500_L2CC_BASE, SZ_4K), + __IO_DEV_DESC(U5500_CLKRST1_BASE, SZ_4K), + __IO_DEV_DESC(U5500_CLKRST2_BASE, SZ_4K), + __IO_DEV_DESC(U5500_CLKRST3_BASE, SZ_4K), + __IO_DEV_DESC(U5500_CLKRST5_BASE, SZ_4K), + __IO_DEV_DESC(U5500_CLKRST6_BASE, SZ_4K), +}; + +static struct resource mbox0_resources[] = { + { + .name = "mbox_peer", + .start = U5500_MBOX0_PEER_START, + .end = U5500_MBOX0_PEER_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_local", + .start = U5500_MBOX0_LOCAL_START, + .end = U5500_MBOX0_LOCAL_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_irq", + .start = MBOX_PAIR0_VIRT_IRQ, + .end = MBOX_PAIR0_VIRT_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource mbox1_resources[] = { + { + .name = "mbox_peer", + .start = U5500_MBOX1_PEER_START, + .end = U5500_MBOX1_PEER_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_local", + .start = U5500_MBOX1_LOCAL_START, + .end = U5500_MBOX1_LOCAL_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_irq", + .start = MBOX_PAIR1_VIRT_IRQ, + .end = MBOX_PAIR1_VIRT_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource mbox2_resources[] = { + { + .name = "mbox_peer", + .start = U5500_MBOX2_PEER_START, + .end = U5500_MBOX2_PEER_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_local", + .start = U5500_MBOX2_LOCAL_START, + .end = U5500_MBOX2_LOCAL_END, + .flags = IORESOURCE_MEM, + }, + { + .name = "mbox_irq", + .start = MBOX_PAIR2_VIRT_IRQ, + .end = MBOX_PAIR2_VIRT_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device mbox0_device = { + .id = 0, + .name = "mbox", + .resource = mbox0_resources, + .num_resources = ARRAY_SIZE(mbox0_resources), +}; + +static struct platform_device mbox1_device = { + .id = 1, + .name = "mbox", + .resource = mbox1_resources, + .num_resources = ARRAY_SIZE(mbox1_resources), +}; + +static struct platform_device mbox2_device = { + .id = 2, + .name = "mbox", + .resource = mbox2_resources, + .num_resources = ARRAY_SIZE(mbox2_resources), }; static struct platform_device *u5500_platform_devs[] __initdata = { @@ -33,19 +140,34 @@ static struct platform_device *u5500_platform_devs[] __initdata = { &u5500_gpio_devs[5], &u5500_gpio_devs[6], &u5500_gpio_devs[7], + &mbox0_device, + &mbox1_device, + &mbox2_device, + &u5500_pwm0_device, + &u5500_pwm1_device, + &u5500_pwm2_device, + &u5500_pwm3_device, }; 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); } void __init u5500_init_devices(void) { + struct amba_device *dev; + ux500_init_devices(); + db5500_dma_init(); + + dev = db5500_add_rtc(); + if (!IS_ERR(dev)) + device_init_wakeup(&dev->dev, true); + platform_add_devices(u5500_platform_devs, ARRAY_SIZE(u5500_platform_devs)); } diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index f21c444edd9..79953b65888 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -16,12 +16,56 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/sys_soc.h> +#include <asm/pmu.h> #include <asm/mach/map.h> #include <mach/hardware.h> #include <mach/setup.h> #include <mach/devices.h> +static struct resource db8500_pmu_resources[] = { + [0] = { + .start = IRQ_DB8500_PMU, + .end = IRQ_DB8500_PMU, + .flags = IORESOURCE_IRQ, + }, +}; + +/* + * The PMU IRQ lines of two cores are wired together into a single interrupt. + * Bounce the interrupt to the other core if it's not ours. + */ +static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) +{ + irqreturn_t ret = handler(irq, dev); + int other = !smp_processor_id(); + + if (ret == IRQ_NONE && cpu_online(other)) + irq_set_affinity(irq, cpumask_of(other)); + + /* + * We should be able to get away with the amount of IRQ_NONEs we give, + * while still having the spurious IRQ detection code kick in if the + * interrupt really starts hitting spuriously. + */ + return ret; +} + +static struct arm_pmu_platdata db8500_pmu_platdata = { + .handle_irq = db8500_pmu_handler, +}; + +static struct platform_device db8500_pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(db8500_pmu_resources), + .resource = db8500_pmu_resources, + .dev.platform_data = &db8500_pmu_platdata, +}; + static struct platform_device *platform_devs[] __initdata = { &u8500_gpio_devs[0], &u8500_gpio_devs[1], @@ -32,51 +76,264 @@ static struct platform_device *platform_devs[] __initdata = { &u8500_gpio_devs[6], &u8500_gpio_devs[7], &u8500_gpio_devs[8], - &u8500_dma40_device, + &ux500_wdt_device, + &db8500_pmu_device, }; -/* minimum static i/o mapping required to boot U8500 platforms */ +#include "devices-db8500.h" + static struct map_desc u8500_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_MTU1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_TWD_BASE, SZ_4K), + __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_UART1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), + __IO_DEV_DESC(U8500_RTC_BASE, SZ_4K), + __IO_DEV_DESC(U8500_MSP0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_MSP1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_MSP2_BASE, SZ_4K), __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K), + __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_STM_REG_BASE, SZ_4K), + {IO_ADDRESS(U8500_BACKUPRAM0_BASE), + __phys_to_pfn(U8500_BACKUPRAM0_BASE), SZ_8K, MT_BACKUP_RAM}, + __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M), + __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), + __IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K), }; static struct map_desc u8500ed_io_desc[] __initdata = { __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), + __IO_DEV_DESC(U8500_MTU1_BASE_ED, SZ_4K), __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), }; static struct map_desc u8500v1_io_desc[] __initdata = { - __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE_V1, SZ_4K), }; -void __init u8500_map_io(void) +static struct map_desc u8500v2_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), +}; +/* + * Functions to differentiate between later ASICs + * We look into the end of the ROM to locate the hardcoded ASIC ID. + * This is only needed to differentiate between minor revisions and + * process variants of an ASIC, the major revisions are encoded in + * the cpuid. + */ +#define U8500_ASIC_ID_LOC_ED_V1 (U8500_BOOT_ROM_BASE + 0x1FFF4) +#define U8500_ASIC_ID_LOC_V2 (U8500_BOOT_ROM_BASE + 0x1DBF4) +#define U8500_ASIC_REV_ED 0x01 +#define U8500_ASIC_REV_V10 0xA0 +#define U8500_ASIC_REV_V11 0xA1 +#define U8500_ASIC_REV_V20 0xB0 +#define U8500_ASIC_REV_V21 0xB1 + +/** + * struct db8500_asic_id - fields of the ASIC ID + * @process: the manufacturing process, 0x40 is 40 nm + * 0x00 is "standard" + * @partnumber: hithereto 0x8500 for DB8500 + * @revision: version code in the series + * This field definion is not formally defined but makes + * sense. + */ +struct db8500_asic_id { + u8 process; + u16 partnumber; + u8 revision; +}; + +/* This isn't going to change at runtime */ +static struct db8500_asic_id db8500_id; + +static void __init get_db8500_asic_id(void) +{ + u32 asicid; + + if (cpu_is_u8500v1() || cpu_is_u8500ed()) + asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1)); + else if (cpu_is_u8500v2()) + asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2)); + else + BUG(); + + db8500_id.process = (asicid >> 24); + db8500_id.partnumber = (asicid >> 16) & 0xFFFFU; + db8500_id.revision = asicid & 0xFFU; +} + +bool cpu_is_u8500v10(void) { - ux500_map_io(); + return (db8500_id.revision == U8500_ASIC_REV_V10); +} + +bool cpu_is_u8500v11(void) +{ + return (db8500_id.revision == U8500_ASIC_REV_V11); +} + +bool cpu_is_u8500v20(void) +{ + return (db8500_id.revision == U8500_ASIC_REV_V20); +} + +bool cpu_is_u8500v21(void) +{ + return (db8500_id.revision == U8500_ASIC_REV_V21); +} +bool cpu_is_u8500v20_or_later(void) +{ + return !cpu_is_u8500v10() && !cpu_is_u8500v11(); +} + +void __init u8500_map_io(void) +{ iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); if (cpu_is_u8500ed()) iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc)); - else + else if (cpu_is_u8500v1()) iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc)); + else if (cpu_is_u8500v2()) + iotable_init(u8500v2_io_desc, ARRAY_SIZE(u8500v2_io_desc)); + + _PRCMU_BASE = __io_address(U8500_PRCMU_BASE); + + /* Read out the ASIC ID as early as we can */ + get_db8500_asic_id(); } +static void __init u8500_earlydrop_fixup(void) +{ + u8500_shrm_device.resource[1].start = IRQ_CA_WAKE_REQ_ED; + u8500_shrm_device.resource[1].end = IRQ_CA_WAKE_REQ_ED; + u8500_shrm_device.resource[2].start = IRQ_AC_READ_NOTIFICATION_0_ED; + u8500_shrm_device.resource[2].end = IRQ_AC_READ_NOTIFICATION_0_ED; + u8500_shrm_device.resource[3].start = IRQ_AC_READ_NOTIFICATION_1_ED; + u8500_shrm_device.resource[3].end = IRQ_AC_READ_NOTIFICATION_1_ED; + u8500_shrm_device.resource[4].start = IRQ_CA_MSG_PEND_NOTIFICATION_0_ED; + u8500_shrm_device.resource[4].end = IRQ_CA_MSG_PEND_NOTIFICATION_0_ED; + u8500_shrm_device.resource[5].start = IRQ_CA_MSG_PEND_NOTIFICATION_1_ED; + u8500_shrm_device.resource[5].end = IRQ_CA_MSG_PEND_NOTIFICATION_1_ED; +} /* * This function is called from the board init */ void __init u8500_init_devices(void) { + struct amba_device *dev; + ux500_init_devices(); + /* Display some ASIC boilerplate */ + pr_info("DB8500: process: %02x, revision ID: 0x%02x\n", + db8500_id.process, db8500_id.revision); if (cpu_is_u8500ed()) - dma40_u8500ed_fixup(); + pr_info("DB8500: Early Drop (ED)\n"); + else if (cpu_is_u8500v10()) + pr_info("DB8500: version 1.0\n"); + else if (cpu_is_u8500v11()) + pr_info("DB8500: version 1.1\n"); + else if (cpu_is_u8500v20()) + pr_info("DB8500: version 2.0\n"); + else if (cpu_is_u8500v21()) + pr_info("DB8500: version 2.1\n"); + else + pr_warning("ASIC: UNKNOWN SILICON VERSION!\n"); + + if (cpu_is_u8500ed()) + u8500_earlydrop_fixup(); + + db8500_dma_init(); + db8500_uart_init(); + + dev = db8500_add_rtc(); + if (!IS_ERR(dev)) + device_init_wakeup(&dev->dev, true); /* Register the platform devices */ platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); return ; } + +#ifdef CONFIG_SYS_SOC +#define U8500_BB_UID_BASE (U8500_BACKUPRAM1_BASE + 0xFC0) +#define U8500_BB_UID_LENGTH 5 + +static ssize_t ux500_get_machine(char *buf, struct sysfs_soc_info *si) +{ + return sprintf(buf, "DB%2x00\n", db8500_id.partnumber); +} + +static ssize_t ux500_get_soc_id(char *buf, struct sysfs_soc_info *si) +{ + void __iomem *uid_base; + int i; + ssize_t sz = 0; + + if (db8500_id.partnumber == 0x85) { + uid_base = __io_address(U8500_BB_UID_BASE); + for (i = 0; i < U8500_BB_UID_LENGTH; i++) + sz += sprintf(buf + sz, "%08x", readl(uid_base + i * sizeof(u32))); + sz += sprintf(buf + sz, "\n"); + } + else { + /* Don't know where it is located for U5500 */ + sz = sprintf(buf, "N/A\n"); + } + + return sz; +} + +static ssize_t ux500_get_revision(char *buf, struct sysfs_soc_info *si) +{ + unsigned int rev = db8500_id.revision; + + if (rev == 0x01) + return sprintf(buf, "%s\n", "ED"); + else if (rev >= 0xA0) + return sprintf(buf, "%d.%d\n" , (rev >> 4) - 0xA + 1, rev & 0xf); + + return sprintf(buf, "%s", "Unknown\n"); +} + +static ssize_t ux500_get_process(char *buf, struct sysfs_soc_info *si) +{ + if (db8500_id.process == 0x00) + return sprintf(buf, "Standard\n"); + + return sprintf(buf, "%02xnm\n", db8500_id.process); +} + +static struct sysfs_soc_info soc_info[] = { + SYSFS_SOC_ATTR_CALLBACK("machine", ux500_get_machine), + SYSFS_SOC_ATTR_VALUE("family", "Ux500"), + SYSFS_SOC_ATTR_CALLBACK("soc_id", ux500_get_soc_id), + SYSFS_SOC_ATTR_CALLBACK("revision", ux500_get_revision), + SYSFS_SOC_ATTR_CALLBACK("process", ux500_get_process), +}; + +static int __init ux500_sys_soc_init(void) +{ + return register_sysfs_soc(soc_info, ARRAY_SIZE(soc_info)); +} + +module_init(ux500_sys_soc_init); +#endif + diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e0fd747e447..908bb057d8d 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -9,97 +9,170 @@ #include <linux/amba/bus.h> #include <linux/io.h> #include <linux/clk.h> +#include <linux/delay.h> +#include <asm/cacheflush.h> #include <asm/hardware/cache-l2x0.h> #include <asm/hardware/gic.h> #include <asm/mach/map.h> -#include <asm/localtimer.h> #include <plat/mtu.h> #include <mach/hardware.h> #include <mach/setup.h> #include <mach/devices.h> +#include <mach/prcmu-fw-api.h> +#include <mach/prcmu-db5500.h> +#include <mach/reboot_reasons.h> #include "clock.h" -static struct map_desc ux500_io_desc[] __initdata = { - __IO_DEV_DESC(UX500_UART0_BASE, SZ_4K), - __IO_DEV_DESC(UX500_UART2_BASE, SZ_4K), +void __iomem *gic_cpu_base_addr; +void __iomem *_PRCMU_BASE; - __IO_DEV_DESC(UX500_GIC_CPU_BASE, SZ_4K), - __IO_DEV_DESC(UX500_GIC_DIST_BASE, SZ_4K), - __IO_DEV_DESC(UX500_L2CC_BASE, SZ_4K), - __IO_DEV_DESC(UX500_TWD_BASE, SZ_4K), - __IO_DEV_DESC(UX500_SCU_BASE, SZ_4K), +#ifdef CONFIG_CACHE_L2X0 +static void __iomem *l2x0_base; +#endif - __IO_DEV_DESC(UX500_CLKRST1_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST2_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST3_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST5_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST6_BASE, SZ_4K), +/* + * The reboot reason string can be 255 characters long and the memory + * in which we save the sw reset reason is 2 bytes. Therefore we need to + * convert the string into a 16 bit pattern. + * + * See file reboot_reasons.h for conversion. + */ +static unsigned short map_cmd_to_code(const char *cmd) +{ + int i; - __IO_DEV_DESC(UX500_MTU0_BASE, SZ_4K), - __IO_DEV_DESC(UX500_MTU1_BASE, SZ_4K), + if (cmd == NULL) + /* normal reboot w/o argument */ + return SW_RESET_NO_ARGUMENT; - __IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K), -}; + /* Search through reboot reason list */ + for (i = 0; i < reboot_reasons_size; i++) { + if (!strcmp(reboot_reasons[i].reason, cmd)) + return reboot_reasons[i].code; + } -static struct amba_device *ux500_amba_devs[] __initdata = { - &ux500_pl031_device, -}; + /* No valid Reboot Reason found */ + return SW_RESET_CRASH; +} -void __init ux500_map_io(void) +void __init ux500_init_devices(void) { - iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc)); +#ifdef CONFIG_CACHE_L2X0 + BUG_ON(!l2x0_base); + + /* + * Unlock Data and Instruction Lock if locked. This is done here + * instead of in l2x0_init since doing it there appears to cause the + * second core boot to occasionaly fail. + */ + if (readl_relaxed(l2x0_base + L2X0_LOCKDOWN_WAY_D) & 0xFF) + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D); + + if (readl_relaxed(l2x0_base + L2X0_LOCKDOWN_WAY_I) & 0xFF) + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I); + +#endif } -void __init ux500_init_devices(void) +static void ux500_restart(char mode, const char *cmd) { - amba_add_devices(ux500_amba_devs, ARRAY_SIZE(ux500_amba_devs)); + unsigned short reset_code; + + reset_code = map_cmd_to_code(cmd); + prcmu_system_reset(reset_code); + + mdelay(1000); + printk("Reboot via PRCMU failed -- System halted\n"); + while (1); } void __init ux500_init_irq(void) { - gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); - gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + void __iomem *dist_base; + + if (cpu_is_u5500()) { + gic_cpu_base_addr = __io_address(U5500_GIC_CPU_BASE); + dist_base = __io_address(U5500_GIC_DIST_BASE); + } else if (cpu_is_u8500()) { + gic_cpu_base_addr = __io_address(U8500_GIC_CPU_BASE); + dist_base = __io_address(U8500_GIC_DIST_BASE); + } else + ux500_unknown_soc(); + + gic_dist_init(0, dist_base, 29); + gic_cpu_init(0, gic_cpu_base_addr); /* * Init clocks here so that they are available for system timer * initialization. */ + if (cpu_is_u5500()) + db5500_prcmu_early_init(); + else { + prcmu_early_init(); + arm_pm_restart = ux500_restart; + } + clk_init(); } #ifdef CONFIG_CACHE_L2X0 -static int ux500_l2x0_init(void) +static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) { - void __iomem *l2x0_base; + /* wait for the operation to complete */ + while (readl_relaxed(reg) & mask) + ; +} - l2x0_base = __io_address(UX500_L2CC_BASE); +static inline void ux500_cache_sync(void) +{ + void __iomem *base = l2x0_base; - /* 64KB way size, 8 way associativity, force WA */ - l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); + writel_relaxed(0, base + L2X0_CACHE_SYNC); + ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); +} - return 0; +/* The L2 cache cannot be turned off in the non-secure world. + Dummy until a secure service is in place */ +static void ux500_l2x0_disable(void) {} + +/* This is only called when doing a kexec, just after turning off the L2 + and L1 cache, and it is surrounded by a spinlock in the generic version. + However, we're not really turning off the L2 cache right now and the + PL310 does not support exclusive accesses (used to implement the spinlock). + So, the invalidation needs to be done without the spinlock. */ +static void ux500_l2x0_inv_all(void) +{ + void __iomem *base = l2x0_base; + uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ + + /* invalidate all ways */ + writel_relaxed(l2x0_way_mask, base + L2X0_INV_WAY); + ux500_cache_wait(base + L2X0_INV_WAY, l2x0_way_mask); + ux500_cache_sync(); } -early_initcall(ux500_l2x0_init); -#endif -static void __init ux500_timer_init(void) +static int ux500_l2x0_init(void) { -#ifdef CONFIG_LOCAL_TIMERS - /* Setup the local timer base */ - twd_base = __io_address(UX500_TWD_BASE); -#endif - /* Setup the MTU base */ - if (cpu_is_u8500ed()) - mtu_base = __io_address(U8500_MTU0_BASE_ED); + if (cpu_is_u5500()) + l2x0_base = __io_address(U5500_L2CC_BASE); + else if (cpu_is_u8500()) + l2x0_base = __io_address(U8500_L2CC_BASE); else - mtu_base = __io_address(UX500_MTU0_BASE); + ux500_unknown_soc(); + + /* 64KB way size, 8 way associativity, force WA */ + l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); + + /* Override invalidate function */ + outer_cache.disable = ux500_l2x0_disable; + outer_cache.inv_all = ux500_l2x0_inv_all; - nmdk_timer_init(); + return 0; } +early_initcall(ux500_l2x0_init); +#endif -struct sys_timer ux500_timer = { - .init = ux500_timer_init, -}; diff --git a/arch/arm/mach-ux500/cw1200-wlan.c b/arch/arm/mach-ux500/cw1200-wlan.c new file mode 100644 index 00000000000..0dc148596fe --- /dev/null +++ b/arch/arm/mach-ux500/cw1200-wlan.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/gfp.h> +#include <linux/err.h> +#include <linux/cw1200-wlan.h> +#include <linux/module.h> + +static const struct wlan1200_platform_data *platform_data; + +void wlan1200_set_platdata(struct wlan1200_platform_data *pdata) +{ + /* + * note, if we get a failure in allocation, we simply drop out of the + * function. If there is so little memory available at initialisation + * time then there is little chance the system is going to run. + */ + + platform_data = kmemdup(pdata, sizeof(struct wlan1200_platform_data), GFP_KERNEL); + if (!platform_data) { + printk(KERN_ERR "%s: failed copying platform data\n", __func__); + return; + } +} +EXPORT_SYMBOL(wlan1200_set_platdata); + +const struct wlan1200_platform_data *wlan1200_get_platform_data(void) +{ + if (!platform_data) + return ERR_PTR(-ENODEV); + + return platform_data; +} +EXPORT_SYMBOL(wlan1200_get_platform_data); + diff --git a/arch/arm/mach-ux500/dcache.c b/arch/arm/mach-ux500/dcache.c new file mode 100644 index 00000000000..b117d4e8283 --- /dev/null +++ b/arch/arm/mach-ux500/dcache.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Cache handler integration and data cache helpers. + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/dma-mapping.h> + +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/outercache.h> +#include <asm/system.h> + +/* + * Values are derived from measurements on HREFP_1.1_V32_OM_S10 running + * u8500-android-2.2_r1.1_v0.21. + * + * A lot of time can be spent trying to figure out the perfect breakpoints but + * for now I've chosen the following simple way. + * + * breakpoint = best_case + (worst_case - best_case) * 0.666 + * The breakpoint is moved slightly towards the worst case because a full + * clean/flush affects the entire system so we should be a bit careful. + * + * BEST CASE: + * Best case is that the cache is empty and the system is idling. The case + * where the cache contains only targeted data could be better in some cases + * but it's hard to do measurements and calculate on that case so I choose the + * easier alternative. + * + * inner_clean_breakpoint = time_2_range_clean_on_empty_cache( + * complete_clean_on_empty_cache_time) + * inner_flush_breakpoint = time_2_range_flush_on_empty_cache( + * complete_flush_on_empty_cache_time) + * + * outer_clean_breakpoint = time_2_range_clean_on_empty_cache( + * complete_clean_on_empty_cache_time) + * outer_flush_breakpoint = time_2_range_flush_on_empty_cache( + * complete_flush_on_empty_cache_time) + * + * WORST CASE: + * Worst case is that the cache is filled with dirty non targeted data that + * will be used after the synchronization and the system is under heavy load. + * + * inner_clean_breakpoint = time_2_range_clean_on_empty_cache( + * complete_clean_on_full_cache_time * 1.5) + * Times 1.5 because it runs on both cores half the time. + * inner_flush_breakpoint = time_2_range_flush_on_empty_cache( + * complete_flush_on_full_cache_time * 1.5 + + * complete_flush_on_full_cache_time / 2) + * Plus "complete_flush_on_full_cache_time / 2" because all data has to be read + * back, here we assume that both cores can fill their cache simultaneously + * (seems to be the case as operations on full and empty inner cache takes + * roughly the same amount of time ie the bus to outer is not the bottle neck). + * + * outer_clean_breakpoint = time_2_range_clean_on_empty_cache( + * complete_clean_on_full_cache_time + + * (complete_clean_on_full_cache_time - + * complete_clean_on_empty_cache_time)) + * Plus "(complete_flush_on_full_cache_time - + * complete_flush_on_empty_cache_time)" because no one else can work when we + * hog the bus with our unecessary transfer. + * outer_flush_breakpoint = time_2_range_flush_on_empty_cache( + * complete_flush_on_full_cache_time * 2 + + * (complete_flush_on_full_cache_time - + * complete_flush_on_empty_cache_time) * 2) + * + * These values might have to be updated if changes are made to the CPU, L2$, + * memory bus or memory. + */ +/* 28930 */ +static const u32 inner_clean_breakpoint = 21324 + (32744 - 21324) * 0.666; +/* 36224 */ +static const u32 inner_flush_breakpoint = 21324 + (43697 - 21324) * 0.666; +/* 254069 */ +static const u32 outer_clean_breakpoint = 68041 + (347363 - 68041) * 0.666; +/* 485414 */ +static const u32 outer_flush_breakpoint = 68041 + (694727 - 68041) * 0.666; + +static void __clean_inner_dcache_all(void *param); +static void clean_inner_dcache_all(void); + +static void __flush_inner_dcache_all(void *param); +static void flush_inner_dcache_all(void); + +static bool is_cache_exclusive(void); + +void drain_cpu_write_buf(void) +{ + dsb(); + outer_cache.sync(); +} + +void clean_cpu_dcache(void *vaddr, u32 paddr, u32 length, bool inner_only, + bool *cleaned_everything) +{ + /* + * There is no problem with exclusive caches here as the Cortex-A9 + * documentation (8.1.4. Exclusive L2 cache) says that when a dirty + * line is moved from L2 to L1 it is first written to mem. Because + * of this there is no way a line can avoid the clean by jumping + * between the cache levels. + */ + *cleaned_everything = true; + + if (length < inner_clean_breakpoint) { + /* Inner clean range */ + dmac_map_area(vaddr, length, DMA_TO_DEVICE); + *cleaned_everything = false; + } else { + clean_inner_dcache_all(); + } + + if (!inner_only) { + /* + * There is currently no outer_cache.clean_all() so we use + * flush instead, which is ok as clean is a subset of flush. + * Clean range and flush range take the same amount of time + * so we can use outer_flush_breakpoint here. + */ + if (length < outer_flush_breakpoint) { + outer_cache.clean_range(paddr, paddr + length); + *cleaned_everything = false; + } else { + outer_cache.flush_all(); + } + } +} + +void flush_cpu_dcache(void *vaddr, u32 paddr, u32 length, bool inner_only, + bool *flushed_everything) +{ + /* + * There might still be stale data in the caches after this call if the + * cache levels are exclusive. The follwing can happen. + * 1. Clean L1 moves the data to L2. + * 2. Speculative prefetch, preemption or loads on the other core moves + * all the data back to L1, any dirty data will be written to mem as a + * result of this. + * 3. Flush L2 does nothing as there is no targeted data in L2. + * 4. Flush L1 moves the data to L2. Notice that this does not happen + * when the cache levels are non-exclusive as clean pages are not + * written to L2 in that case. + * 5. Stale data is still present in L2! + * I see two possible solutions, don't use exclusive caches or + * (temporarily) disable prefetching to L1, preeemption and the other + * core. + * + * A situation can occur where the operation does not seem atomic from + * the other core's point of view, even on a non-exclusive cache setup. + * Replace step 2 in the previous scenarion with a write from the other + * core. The other core will write on top of the old data but the + * result will not be written to memory. One would expect either that + * the write was performed on top of the old data and was written to + * memory (the write occured before the flush) or that the write was + * performed on top of the new data and was not written to memory (the + * write occured after the flush). The same problem can occur with one + * core if kernel preemption is enabled. The solution is to + * (temporarily) disable the other core and preemption. I can't think + * of any situation where this would be a problem and disabling the + * other core for the duration of this call is mighty expensive so for + * now I just ignore the problem. + */ + + *flushed_everything = true; + + if (!inner_only) { + /* + * Beautiful solution for the exclusive problems :) + */ + if (is_cache_exclusive()) + panic("%s can't handle exclusive CPU caches\n", + __func__); + + if (length < inner_clean_breakpoint) { + /* Inner clean range */ + dmac_map_area(vaddr, length, DMA_TO_DEVICE); + *flushed_everything = false; + } else { + clean_inner_dcache_all(); + } + + if (length < outer_flush_breakpoint) { + outer_cache.flush_range(paddr, paddr + length); + *flushed_everything = false; + } else { + outer_cache.flush_all(); + } + } + + if (length < inner_flush_breakpoint) { + /* Inner flush range */ + dmac_flush_range(vaddr, (void *)((u32)vaddr + length)); + *flushed_everything = false; + } else { + flush_inner_dcache_all(); + } +} + +bool speculative_data_prefetch(void) +{ + return true; +} + +u32 get_dcache_granularity(void) +{ + return 32; +} + +/* + * Local functions + */ + +static void __clean_inner_dcache_all(void *param) +{ + __cpuc_clean_dcache_all(); +} + +static void clean_inner_dcache_all(void) +{ + on_each_cpu(__clean_inner_dcache_all, NULL, 1); +} + +static void __flush_inner_dcache_all(void *param) +{ + __cpuc_flush_dcache_all(); +} + +static void flush_inner_dcache_all(void) +{ + on_each_cpu(__flush_inner_dcache_all, NULL, 1); +} + +static bool is_cache_exclusive(void) +{ + static const u32 CA9_ACTLR_EXCL = 0x80; + + u32 armv7_actlr; + + asm ( + "mrc p15, 0, %0, c1, c0, 1" + : "=r" (armv7_actlr) + ); + + if (armv7_actlr & CA9_ACTLR_EXCL) + return true; + else + return false; +} diff --git a/arch/arm/mach-ux500/devices-cg2900-u5500.c b/arch/arm/mach-ux500/devices-cg2900-u5500.c new file mode 100644 index 00000000000..fac30589696 --- /dev/null +++ b/arch/arm/mach-ux500/devices-cg2900-u5500.c @@ -0,0 +1,65 @@ +/* + * arch/arm/mach-ux500/devices-cg2900-u5500.c + * + * Copyright (C) ST-Ericsson SA 2010 + * Authors: + * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson. + * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson. + * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson. + * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson. + * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2 + * + * Board specific device support for the Linux Bluetooth HCI H:4 Driver + * for ST-Ericsson connectivity controller. + */ + +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/clk.h> +#include <linux/types.h> +#include <linux/mfd/cg2900.h> +#include <linux/mfd/abx500/ab5500.h> + +#include <mach/prcmu-db5500.h> + +#include "devices-cg2900.h" + +/* prcmu resout1 pin is used for CG2900 reset*/ +void dcg2900_enable_chip(struct cg2900_chip_dev *dev) +{ + struct dcg2900_info *info = dev->b_data; + + clk_enable(info->lpoclk); + /* + * Due to a bug in CG2900 we cannot just set GPIO high to enable + * the chip. We must wait more than 100 msecs before enbling the + * chip. + * - Set PDB to low. + * - Wait for 100 msecs + * - Set PDB to high. + */ + prcmu_resetout(1, 0); + schedule_timeout_uninterruptible(msecs_to_jiffies( + CHIP_ENABLE_PDB_LOW_TIMEOUT)); + prcmu_resetout(1, 1); +} + +void dcg2900_disable_chip(struct cg2900_chip_dev *dev) +{ + struct dcg2900_info *info = dev->b_data; + + prcmu_resetout(1, 0); + clk_disable(info->lpoclk); +} + +int dcg2900_setup(struct cg2900_chip_dev *dev, + struct dcg2900_info *info) +{ + info->lpoclk = clk_get(dev->dev, "lpoclk"); + if (IS_ERR(info->lpoclk)) + return PTR_ERR(info->lpoclk); + + return 0; +} diff --git a/arch/arm/mach-ux500/devices-cg2900-u8500.c b/arch/arm/mach-ux500/devices-cg2900-u8500.c new file mode 100644 index 00000000000..08332206beb --- /dev/null +++ b/arch/arm/mach-ux500/devices-cg2900-u8500.c @@ -0,0 +1,181 @@ +/* + * arch/arm/mach-ux500/devices-cg2900-u8500.c + * + * Copyright (C) ST-Ericsson SA 2010 + * Authors: + * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson. + * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson. + * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson. + * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson. + * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2 + * + * Board specific device support for the Linux Bluetooth HCI H:4 Driver + * for ST-Ericsson connectivity controller. + */ + +#include <asm/byteorder.h> +#include <asm-generic/errno-base.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/mfd/cg2900.h> +#include <linux/mfd/abx500/ab5500.h> +#include <plat/pincfg.h> + +#include "devices-cg2900.h" + +void dcg2900_enable_chip(struct cg2900_chip_dev *dev) +{ + struct dcg2900_info *info = dev->b_data; + + if (info->gbf_gpio == -1) + return; + + /* + * Due to a bug in CG2900 we cannot just set GPIO high to enable + * the chip. We must wait more than 100 msecs before enabling the + * chip. + * - Set PDB to low. + * - Wait for 100 msecs + * - Set PDB to high. + */ + gpio_set_value(info->gbf_gpio, 0); + schedule_timeout_uninterruptible(msecs_to_jiffies( + CHIP_ENABLE_PDB_LOW_TIMEOUT)); + + if (info->pmuen_gpio != -1) { + /* + * We must first set PMU_EN pin high and then wait 300 us before + * setting the GBF_EN high. + */ + gpio_set_value(info->pmuen_gpio, 1); + udelay(CHIP_ENABLE_PMU_EN_TIMEOUT); + } + + gpio_set_value(info->gbf_gpio, 1); +} + +void dcg2900_disable_chip(struct cg2900_chip_dev *dev) +{ + struct dcg2900_info *info = dev->b_data; + + if (info->gbf_gpio != -1) + gpio_set_value(info->gbf_gpio, 0); + if (info->pmuen_gpio != -1) + gpio_set_value(info->pmuen_gpio, 0); +} + +int dcg2900_setup(struct cg2900_chip_dev *dev, + struct dcg2900_info *info) +{ + int err = 0; + struct resource *resource; + const char *gbf_name; + const char *bt_name = NULL; + const char *pmuen_name = NULL; + + resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO, + "gbf_ena_reset"); + if (!resource) { + dev_err(dev->dev, "GBF GPIO does not exist\n"); + err = -EINVAL; + goto err_handling; + } + + info->gbf_gpio = resource->start; + gbf_name = resource->name; + + resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO, + "bt_enable"); + /* BT Enable GPIO may not exist */ + if (resource) { + info->bt_gpio = resource->start; + bt_name = resource->name; + } + + resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO, + "pmu_en"); + /* PMU_EN GPIO may not exist */ + if (resource) { + info->pmuen_gpio = resource->start; + pmuen_name = resource->name; + } + + /* Now setup the GPIOs */ + err = gpio_request(info->gbf_gpio, gbf_name); + if (err < 0) { + dev_err(dev->dev, "gpio_request %s failed with err: %d\n", + gbf_name, err); + goto err_handling; + } + + err = gpio_direction_output(info->gbf_gpio, 0); + if (err < 0) { + dev_err(dev->dev, + "gpio_direction_output %s failed with err: %d\n", + gbf_name, err); + goto err_handling_free_gpio_gbf; + } + + if (!pmuen_name) + goto set_bt_gpio; + + err = gpio_request(info->pmuen_gpio, pmuen_name); + if (err < 0) { + dev_err(dev->dev, "gpio_request %s failed with err: %d\n", + pmuen_name, err); + goto err_handling_free_gpio_gbf; + } + + err = gpio_direction_output(info->pmuen_gpio, 0); + if (err < 0) { + dev_err(dev->dev, + "gpio_direction_output %s failed with err: %d\n", + pmuen_name, err); + goto err_handling_free_gpio_pmuen; + } + +set_bt_gpio: + if (!bt_name) + goto finished; + + err = gpio_request(info->bt_gpio, bt_name); + if (err < 0) { + dev_err(dev->dev, "gpio_request %s failed with err: %d\n", + bt_name, err); + goto err_handling_free_gpio_pmuen; + } + + err = gpio_direction_output(info->bt_gpio, 1); + if (err < 0) { + dev_err(dev->dev, + "gpio_direction_output %s failed with err: %d\n", + bt_name, err); + goto err_handling_free_gpio_bt; + } + +finished: + + return 0; + +err_handling_free_gpio_bt: + gpio_free(info->bt_gpio); + info->bt_gpio = -1; +err_handling_free_gpio_pmuen: + if (info->pmuen_gpio != -1) { + gpio_free(info->pmuen_gpio); + info->pmuen_gpio = -1; + } +err_handling_free_gpio_gbf: + gpio_free(info->gbf_gpio); + info->gbf_gpio = -1; +err_handling: + + return err; +} diff --git a/arch/arm/mach-ux500/devices-cg2900.c b/arch/arm/mach-ux500/devices-cg2900.c new file mode 100644 index 00000000000..a48f2ee34d2 --- /dev/null +++ b/arch/arm/mach-ux500/devices-cg2900.c @@ -0,0 +1,241 @@ +/* + * arch/arm/mach-ux500/devices-cg2900.c + * + * Copyright (C) ST-Ericsson SA 2010 + * Authors: + * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson. + * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson. + * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson. + * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson. + * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2 + * + * Board specific device support for the Linux Bluetooth HCI H:4 Driver + * for ST-Ericsson connectivity controller. + */ + +#define NAME "devices-cg2900" +#define pr_fmt(fmt) NAME ": " fmt "\n" + +#include <asm/byteorder.h> +#include <asm-generic/errno-base.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/mfd/cg2900.h> +#include <plat/pincfg.h> + +#include "devices-cg2900.h" + +#define BT_VS_POWER_SWITCH_OFF 0xFD40 + +#define H4_HEADER_LENGTH 0x01 +#define BT_HEADER_LENGTH 0x03 + +#define STLC2690_HCI_REV 0x0600 +#define CG2900_PG1_HCI_REV 0x0101 +#define CG2900_PG2_HCI_REV 0x0200 +#define CG2900_PG1_SPECIAL_HCI_REV 0x0700 + +struct vs_power_sw_off_cmd { + __le16 op_code; + u8 len; + u8 gpio_0_7_pull_up; + u8 gpio_8_15_pull_up; + u8 gpio_16_20_pull_up; + u8 gpio_0_7_pull_down; + u8 gpio_8_15_pull_down; + u8 gpio_16_20_pull_down; +} __packed; + +static struct sk_buff *dcg2900_get_power_switch_off_cmd + (struct cg2900_chip_dev *dev, u16 *op_code) +{ + struct sk_buff *skb; + struct vs_power_sw_off_cmd *cmd; + struct dcg2900_info *info; + int i; + + /* If connected chip does not support the command return NULL */ + if (CG2900_PG1_SPECIAL_HCI_REV != dev->chip.hci_revision && + CG2900_PG1_HCI_REV != dev->chip.hci_revision && + CG2900_PG2_HCI_REV != dev->chip.hci_revision) + return NULL; + + dev_dbg(dev->dev, "Generating PowerSwitchOff command\n"); + + info = dev->b_data; + + skb = alloc_skb(sizeof(*cmd) + H4_HEADER_LENGTH, GFP_KERNEL); + if (!skb) { + dev_err(dev->dev, "Could not allocate skb\n"); + return NULL; + } + + skb_reserve(skb, H4_HEADER_LENGTH); + cmd = (struct vs_power_sw_off_cmd *)skb_put(skb, sizeof(*cmd)); + cmd->op_code = cpu_to_le16(BT_VS_POWER_SWITCH_OFF); + cmd->len = sizeof(*cmd) - BT_HEADER_LENGTH; + /* + * Enter system specific GPIO settings here: + * Section data[3-5] is GPIO pull-up selection + * Section data[6-8] is GPIO pull-down selection + * Each section is a bitfield where + * - byte 0 bit 0 is GPIO 0 + * - byte 0 bit 1 is GPIO 1 + * - up to + * - byte 2 bit 4 which is GPIO 20 + * where each bit means: + * - 0: No pull-up / no pull-down + * - 1: Pull-up / pull-down + * All GPIOs are set as input. + */ + if (!info->sleep_gpio_set) { + struct cg2900_platform_data *pf_data; + + pf_data = dev_get_platdata(dev->dev); + for (i = 0; i < 8; i++) { + if (pf_data->gpio_sleep[i] == CG2900_PULL_UP) + info->gpio_0_7_pull_up |= (1 << i); + else if (pf_data->gpio_sleep[i] == CG2900_PULL_DN) + info->gpio_0_7_pull_down |= (1 << i); + } + for (i = 8; i < 16; i++) { + if (pf_data->gpio_sleep[i] == CG2900_PULL_UP) + info->gpio_8_15_pull_up |= (1 << (i - 8)); + else if (pf_data->gpio_sleep[i] == CG2900_PULL_DN) + info->gpio_8_15_pull_down |= (1 << (i - 8)); + } + for (i = 16; i < 21; i++) { + if (pf_data->gpio_sleep[i] == CG2900_PULL_UP) + info->gpio_16_20_pull_up |= (1 << (i - 16)); + else if (pf_data->gpio_sleep[i] == CG2900_PULL_DN) + info->gpio_16_20_pull_down |= (1 << (i - 16)); + } + info->sleep_gpio_set = true; + } + cmd->gpio_0_7_pull_up = info->gpio_0_7_pull_up; + cmd->gpio_8_15_pull_up = info->gpio_8_15_pull_up; + cmd->gpio_16_20_pull_up = info->gpio_16_20_pull_up; + cmd->gpio_0_7_pull_down = info->gpio_0_7_pull_down; + cmd->gpio_8_15_pull_down = info->gpio_8_15_pull_down; + cmd->gpio_16_20_pull_down = info->gpio_16_20_pull_down; + + + if (op_code) + *op_code = BT_VS_POWER_SWITCH_OFF; + + return skb; +} + +static int dcg2900_init(struct cg2900_chip_dev *dev) +{ + int err = 0; + struct dcg2900_info *info; + + /* First retrieve and save the resources */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(dev->dev, "Could not allocate dcg2900_info\n"); + return -ENOMEM; + } + + info->gbf_gpio = -1; + info->pmuen_gpio = -1; + info->bt_gpio = -1; + + if (!dev->pdev->num_resources) { + dev_dbg(dev->dev, "No resources available\n"); + goto finished; + } + + err = dcg2900_setup(dev, info); + if (err) + goto err_handling; + +finished: + dev->b_data = info; + return 0; + +err_handling: + kfree(info); + + return err; +} + +static void dcg2900_exit(struct cg2900_chip_dev *dev) +{ + struct dcg2900_info *info = dev->b_data; + + dcg2900_disable_chip(dev); + if (info->bt_gpio != -1) + gpio_free(info->bt_gpio); + if (info->pmuen_gpio != -1) + gpio_free(info->pmuen_gpio); + if (info->gbf_gpio != -1) + gpio_free(info->gbf_gpio); + kfree(info); + dev->b_data = NULL; +} + +#ifdef CONFIG_MFD_CG2900_UART +static int dcg2900_disable_uart(struct cg2900_chip_dev *dev) +{ + int err; + struct cg2900_platform_data *pdata = dev_get_platdata(dev->dev); + + /* + * Without this delay we get interrupt on CTS immediately + * due to some turbulences on this line. + */ + mdelay(4); + + /* Disable UART functions. */ + err = nmk_config_pins(pdata->uart.uart_disabled, + pdata->uart.n_uart_gpios); + if (err) + goto error; + + return 0; + +error: + (void)nmk_config_pins(pdata->uart.uart_enabled, + pdata->uart.n_uart_gpios); + dev_err(dev->dev, "Cannot set interrupt (%d)\n", err); + return err; +} + +static int dcg2900_enable_uart(struct cg2900_chip_dev *dev) +{ + int err; + struct cg2900_platform_data *pdata = dev_get_platdata(dev->dev); + + /* Restore UART settings. */ + err = nmk_config_pins(pdata->uart.uart_enabled, + pdata->uart.n_uart_gpios); + if (err) + dev_err(dev->dev, "Unable to enable UART (%d)\n", err); + + return err; +} +#endif /* CONFIG_MFD_CG2900_UART */ + +void dcg2900_init_platdata(struct cg2900_platform_data *data) +{ + data->init = dcg2900_init; + data->exit = dcg2900_exit; + data->enable_chip = dcg2900_enable_chip; + data->disable_chip = dcg2900_disable_chip; + data->get_power_switch_off_cmd = dcg2900_get_power_switch_off_cmd; +#ifdef CONFIG_MFD_CG2900_UART + data->uart.enable_uart = dcg2900_enable_uart; + data->uart.disable_uart = dcg2900_disable_uart; +#endif /* CONFIG_MFD_CG2900_UART */ +} diff --git a/arch/arm/mach-ux500/devices-cg2900.h b/arch/arm/mach-ux500/devices-cg2900.h new file mode 100644 index 00000000000..5a445d965f1 --- /dev/null +++ b/arch/arm/mach-ux500/devices-cg2900.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Par-Gunnar Hjalmdahl <par-gunnar.p.hjalmdahl@stericsson.com> + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_CG2900_H +#define __DEVICES_CG2900_H + +#include <linux/mfd/cg2900.h> +#include <linux/clk.h> + +#define CHIP_ENABLE_PDB_LOW_TIMEOUT 100 /* ms */ +#define CHIP_ENABLE_PMU_EN_TIMEOUT 300 /* us */ + +struct dcg2900_info { + int gbf_gpio; + int pmuen_gpio; + int bt_gpio; + bool sleep_gpio_set; + u8 gpio_0_7_pull_up; + u8 gpio_8_15_pull_up; + u8 gpio_16_20_pull_up; + u8 gpio_0_7_pull_down; + u8 gpio_8_15_pull_down; + u8 gpio_16_20_pull_down; + struct clk *lpoclk; +}; + +extern void dcg2900_enable_chip(struct cg2900_chip_dev *dev); +extern void dcg2900_disable_chip(struct cg2900_chip_dev *dev); +extern int dcg2900_setup(struct cg2900_chip_dev *dev, + struct dcg2900_info *info); + +/** + * dcg2900_init_platdata() - Initializes platform data with callback functions. + * @data: Platform data. + */ +extern void dcg2900_init_platdata(struct cg2900_platform_data *data); + +#endif /* __DEVICES_CG2900_H */ diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c new file mode 100644 index 00000000000..9c70ace7dda --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/pm.h> + +extern struct dev_power_domain ux500_dev_power_domain; + +#include <mach/hardware.h> + +#include "devices-common.h" + +struct amba_device * +dbx500_add_amba_device(const char *init_name, resource_size_t base, + int irq, void *pdata, unsigned int periphid, + const char *name) +{ + struct amba_device *dev; + int ret; + + dev = kzalloc(sizeof *dev, GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->dev.init_name = init_name; + + dev->res.start = base; + dev->res.end = base + SZ_4K - 1; + dev->res.flags = IORESOURCE_MEM; + + dev->dma_mask = DMA_BIT_MASK(32); + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.pwr_domain = &ux500_dev_power_domain; + + dev->irq[0] = irq; + dev->irq[1] = NO_IRQ; + + dev->periphid = periphid; + dev->name = name; + + dev->dev.platform_data = pdata; + + ret = amba_device_register(dev, &iomem_resource); + if (ret) { + kfree(dev); + return ERR_PTR(ret); + } + + return dev; +} + +static struct platform_device * +dbx500_add_platform_device(const char *name, int id, void *pdata, + struct resource *res, int resnum) +{ + struct platform_device *dev; + int ret; + + dev = platform_device_alloc(name, id); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + dev->dev.pwr_domain = &ux500_dev_power_domain; + + ret = platform_device_add_resources(dev, res, resnum); + if (ret) + goto out_free; + + dev->dev.platform_data = pdata; + + ret = platform_device_add(dev); + if (ret) + goto out_free; + + return dev; + +out_free: + platform_device_put(dev); + return ERR_PTR(ret); +} + +struct platform_device * +dbx500_add_platform_device_4k1irq(const char *name, int id, + resource_size_t base, + int irq, void *pdata) +{ + struct resource resources[] = { + [0] = { + .start = base, + .end = base + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = irq, + .end = irq, + .flags = IORESOURCE_IRQ, + } + }; + + return dbx500_add_platform_device(name, id, pdata, resources, + ARRAY_SIZE(resources)); +} diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h new file mode 100644 index 00000000000..c3c14717584 --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_COMMON_H +#define __DEVICES_COMMON_H + +#include <mach/uart.h> + +extern struct amba_device * +dbx500_add_amba_device(const char *init_name, resource_size_t base, + int irq, void *pdata, unsigned int periphid, + const char *name); + +extern struct platform_device * +dbx500_add_platform_device_4k1irq(const char *name, int id, + resource_size_t base, + int irq, void *pdata); + +struct stm_msp_controller; + +static inline struct amba_device * +dbx500_add_msp_spi(const char *name, resource_size_t base, int irq, + struct stm_msp_controller *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, MSP_PER_ID, + NULL); +} + +struct pl022_ssp_controller; + +static inline struct amba_device * +dbx500_add_spi(const char *init_name, resource_size_t base, int irq, + struct pl022_ssp_controller *pdata) +{ + const char *name = NULL; + + if (cpu_is_u5500()) + name = "db5500-spi"; + + return dbx500_add_amba_device(init_name, base, irq, pdata, SPI_PER_ID, + name); +} + +struct mmci_platform_data; + +static inline struct amba_device * +dbx500_add_sdi(const char *name, resource_size_t base, int irq, + struct mmci_platform_data *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, SDI_PER_ID, + NULL); +} + +static inline struct amba_device * +dbx500_add_uart(const char *name, resource_size_t base, int irq, + struct uart_amba_plat_data *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0, NULL); +} + +struct nmk_i2c_controller; + +static inline struct platform_device * +dbx500_add_i2c(int id, resource_size_t base, int irq, + struct nmk_i2c_controller *pdata) +{ + return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq, + pdata); +} + +struct msp_i2s_platform_data; + +static inline struct platform_device * +dbx500_add_msp_i2s(int id, resource_size_t base, int irq, + struct msp_i2s_platform_data *pdata) +{ + return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq, + pdata); +} + +static inline struct amba_device * +dbx500_add_rtc(resource_size_t base, int irq) +{ + return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, + RTC_PER_ID, NULL); +} + +#endif diff --git a/arch/arm/mach-ux500/devices-db5500.c b/arch/arm/mach-ux500/devices-db5500.c index 33e5b56bebb..d2a5bc731d4 100644 --- a/arch/arm/mach-ux500/devices-db5500.c +++ b/arch/arm/mach-ux500/devices-db5500.c @@ -2,25 +2,68 @@ * Copyright (C) ST-Ericsson SA 2010 * * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * for the System Trace Module part. + * * License terms: GNU General Public License (GPL) version 2 */ #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> #include <linux/gpio.h> #include <mach/hardware.h> #include <mach/devices.h> +#include <video/mcde.h> +#include <mach/db5500-regs.h> + +#include <mach/prcmu-fw-api.h> + +#include <trace/stm.h> + +#define GPIO_DATA(_name, first, num) \ + { \ + .name = _name, \ + .first_gpio = first, \ + .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ + .num_gpio = num, \ + } + +#define GPIO_RESOURCE(block) \ + { \ + .start = U5500_GPIOBANK##block##_BASE, \ + .end = U5500_GPIOBANK##block##_BASE + 127, \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = IRQ_DB5500_GPIO##block, \ + .end = IRQ_DB5500_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ + } + +#define GPIO_DEVICE(block) \ + { \ + .name = "gpio", \ + .id = block, \ + .num_resources = 2, \ + .resource = &u5500_gpio_resources[block * 2], \ + .dev = { \ + .platform_data = &u5500_gpio_data[block], \ + }, \ + } + static struct nmk_gpio_platform_data u5500_gpio_data[] = { - GPIO_DATA("GPIO-0-31", 0), - GPIO_DATA("GPIO-32-63", 32), /* 36..63 not routed to pin */ - GPIO_DATA("GPIO-64-95", 64), /* 83..95 not routed to pin */ - GPIO_DATA("GPIO-96-127", 96), /* 102..127 not routed to pin */ - GPIO_DATA("GPIO-128-159", 128), /* 149..159 not routed to pin */ - GPIO_DATA("GPIO-160-191", 160), - GPIO_DATA("GPIO-192-223", 192), - GPIO_DATA("GPIO-224-255", 224), /* 228..255 not routed to pin */ + GPIO_DATA("GPIO-0-31", 0, 32), + GPIO_DATA("GPIO-32-63", 32, 4), /* 36..63 not routed to pin */ + GPIO_DATA("GPIO-64-95", 64, 19), /* 83..95 not routed to pin */ + GPIO_DATA("GPIO-96-127", 96, 6), /* 102..127 not routed to pin */ + GPIO_DATA("GPIO-128-159", 128, 21), /* 149..159 not routed to pin */ + GPIO_DATA("GPIO-160-191", 160, 32), + GPIO_DATA("GPIO-192-223", 192, 32), + GPIO_DATA("GPIO-224-255", 224, 4), /* 228..255 not routed to pin */ }; static struct resource u5500_gpio_resources[] = { @@ -44,3 +87,226 @@ struct platform_device u5500_gpio_devs[] = { GPIO_DEVICE(6), GPIO_DEVICE(7), }; + +#define U5500_PWM_SIZE 0x20 +static struct resource u5500_pwm0_resource[] = { + { + .name = "PWM_BASE", + .start = U5500_PWM_BASE, + .end = U5500_PWM_BASE + U5500_PWM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource u5500_pwm1_resource[] = { + { + .name = "PWM_BASE", + .start = U5500_PWM_BASE + U5500_PWM_SIZE, + .end = U5500_PWM_BASE + U5500_PWM_SIZE * 2 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource u5500_pwm2_resource[] = { + { + .name = "PWM_BASE", + .start = U5500_PWM_BASE + U5500_PWM_SIZE * 2, + .end = U5500_PWM_BASE + U5500_PWM_SIZE * 3 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource u5500_pwm3_resource[] = { + { + .name = "PWM_BASE", + .start = U5500_PWM_BASE + U5500_PWM_SIZE * 3, + .end = U5500_PWM_BASE + U5500_PWM_SIZE * 4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device u5500_pwm0_device = { + .id = 0, + .name = "pwm", + .resource = u5500_pwm0_resource, + .num_resources = ARRAY_SIZE(u5500_pwm0_resource), +}; + +struct platform_device u5500_pwm1_device = { + .id = 1, + .name = "pwm", + .resource = u5500_pwm1_resource, + .num_resources = ARRAY_SIZE(u5500_pwm1_resource), +}; + +struct platform_device u5500_pwm2_device = { + .id = 2, + .name = "pwm", + .resource = u5500_pwm2_resource, + .num_resources = ARRAY_SIZE(u5500_pwm2_resource), +}; + +struct platform_device u5500_pwm3_device = { + .id = 3, + .name = "pwm", + .resource = u5500_pwm3_resource, + .num_resources = ARRAY_SIZE(u5500_pwm3_resource), +}; + +static struct resource mcde_resources[] = { + [0] = { + .name = MCDE_IO_AREA, + .start = U5500_MCDE_BASE, + .end = U5500_MCDE_BASE + U5500_MCDE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = MCDE_IO_AREA, + .start = U5500_DSI_LINK1_BASE, + .end = U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = MCDE_IO_AREA, + .start = U5500_DSI_LINK2_BASE, + .end = U5500_DSI_LINK2_BASE + U5500_DSI_LINK_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [3] = { + .name = MCDE_IRQ, + .start = IRQ_DB5500_DISP, + .end = IRQ_DB5500_DISP, + .flags = IORESOURCE_IRQ, + }, +}; + +static int mcde_platform_enable_dsipll(void) +{ + return prcmu_enable_dsipll(); +} + +static int mcde_platform_disable_dsipll(void) +{ + return prcmu_disable_dsipll(); +} + +static int mcde_platform_set_display_clocks(void) +{ + return prcmu_set_display_clocks(); +} + +static struct mcde_platform_data mcde_pdata = { + .num_dsilinks = 2, + .syncmux = 0x01, + .num_channels = 2, + .num_overlays = 3, + .regulator_vana_id = "v-ana", + .regulator_mcde_epod_id = "vsupply", + .regulator_esram_epod_id = "v-esram34", + .clock_dsi_id = "hdmi", + .clock_dsi_lp_id = "tv", + .clock_mcde_id = "mcde", + .platform_set_clocks = mcde_platform_set_display_clocks, + .platform_enable_dsipll = mcde_platform_enable_dsipll, + .platform_disable_dsipll = mcde_platform_disable_dsipll, +}; + +struct platform_device ux500_mcde_device = { + .name = "mcde", + .id = -1, + .dev = { + .platform_data = &mcde_pdata, + }, + .num_resources = ARRAY_SIZE(mcde_resources), + .resource = mcde_resources, +}; + +static struct resource b2r2_resources[] = { + [0] = { + .start = U5500_B2R2_BASE, + .end = U5500_B2R2_BASE + ((4*1024)-1), + .name = "b2r2_base", + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "B2R2_IRQ", + .start = IRQ_DB5500_B2R2, + .end = IRQ_DB5500_B2R2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ux500_b2r2_device = { + .name = "b2r2", + .id = 0, + .dev = { + .init_name = "b2r2_bus", + .coherent_dma_mask = ~0, + }, + .num_resources = ARRAY_SIZE(b2r2_resources), + .resource = b2r2_resources, +}; + +#ifdef CONFIG_STM_TRACE +/* TODO */ +static void stm_disable_modem_on_mipi34(void) +{ +} + +/* TODO */ +static void stm_enable_modem_on_mipi34(void) +{ +} + +/* TODO */ +static int stm_enable_mipi34(void) +{ + return 0; +} + +/* TODO */ +static int stm_disable_mipi34(void) +{ + return 0; +} + +/* TODO */ +static int stm_enable_ape_modem_mipi60(void) +{ + return 0; +} + +/* TODO */ +static int stm_disable_ape_modem_mipi60(void) +{ + return 0; +} + +static struct stm_platform_data stm_pdata = { + .regs_phys_base = U5500_STM_REG_BASE, + .channels_phys_base = U5500_STM_BASE, + .periph_id = 0xEC0D3800, + .cell_id = 0x0DF005B1, + /* + * These are the channels used by NMF and some external softwares + * expect the NMF traces to be output on these channels + * For legacy reason, we need to reserve them. + * NMF channels reserved HOSTEE (151) + */ + .channels_reserved = {151, -1}, + .ste_enable_modem_on_mipi34 = stm_enable_modem_on_mipi34, + .ste_disable_modem_on_mipi34 = stm_disable_modem_on_mipi34, + .ste_gpio_enable_mipi34 = stm_enable_mipi34, + .ste_gpio_disable_mipi34 = stm_disable_mipi34, + .ste_gpio_enable_ape_modem_mipi60 = stm_enable_ape_modem_mipi60, + .ste_gpio_disable_ape_modem_mipi60 = stm_disable_ape_modem_mipi60, +}; + +struct platform_device ux500_stm_device = { + .name = "stm", + .id = -1, + .dev = { + .platform_data = &stm_pdata, + }, +}; +#endif /* CONFIG_STM_TRACE */ diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h new file mode 100644 index 00000000000..82263e04e3a --- /dev/null +++ b/arch/arm/mach-ux500/devices-db5500.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_DB5500_H +#define __DEVICES_DB5500_H + +#include "devices-common.h" + +#define db5500_add_i2c1(pdata) \ + dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata) +#define db5500_add_i2c2(pdata) \ + dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata) +#define db5500_add_i2c3(pdata) \ + dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata) + +struct db5500_keypad_platform_data; + +static inline struct platform_device * +db5500_add_keypad(struct db5500_keypad_platform_data *pdata) +{ + return dbx500_add_platform_device_4k1irq("db5500-keypad", -1, + U5500_KEYPAD_BASE, + IRQ_DB5500_KBD, pdata); +} + +#define db5500_add_msp0_i2s(pdata) \ + dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_i2s(pdata) \ + dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_i2s(pdata) \ + dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) + +#define db5500_add_msp0_spi(pdata) \ + dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_spi(pdata) \ + dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_spi(pdata) \ + dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) + +#define db5500_add_rtc() \ + dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC); + +#define db5500_add_sdi0(pdata) \ + dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata) +#define db5500_add_sdi1(pdata) \ + dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata) +#define db5500_add_sdi2(pdata) \ + dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata) +#define db5500_add_sdi3(pdata) \ + dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata) +#define db5500_add_sdi4(pdata) \ + dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata) + +#define db5500_add_spi0(pdata) \ + dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata) +#define db5500_add_spi1(pdata) \ + dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata) +#define db5500_add_spi2(pdata) \ + dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata) +#define db5500_add_spi3(pdata) \ + dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata) + +#define db5500_add_uart0() \ + dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, NULL) +#define db5500_add_uart1() \ + dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, NULL) +#define db5500_add_uart2() \ + dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, NULL) +#define db5500_add_uart3() \ + dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, NULL) + +#endif diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c index 82290342194..900c77c1057 100644 --- a/arch/arm/mach-ux500/devices-db8500.c +++ b/arch/arm/mach-ux500/devices-db8500.c @@ -2,6 +2,10 @@ * Copyright (C) ST-Ericsson SA 2010 * * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * + * Author: Pierre Peiffer <pierre.peiffer@stericsson.com> for ST-Ericsson. + * for the System Trace Module part. + * * License terms: GNU General Public License (GPL) version 2 */ @@ -9,26 +13,76 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/amba/bus.h> +#include <plat/pincfg.h> -#include <plat/ste_dma40.h> - +#include <mach/devices.h> #include <mach/hardware.h> #include <mach/setup.h> -#include "ste-dma40-db8500.h" +#include <video/mcde.h> +#include <mach/prcmu-fw-api.h> +#include <mach/prcmu-regs.h> +#include <mach/hsi.h> +#include <mach/ste-dma40-db8500.h> + +#include <trace/stm.h> + +#include "pins-db8500.h" +#include "pm/pm.h" + +#include <plat/ste_dma40.h> + +#define GPIO_DATA(_name, first, num) \ + { \ + .name = _name, \ + .first_gpio = first, \ + .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ + .num_gpio = num, \ + .get_secondary_status = ux500_pm_gpio_read_wake_up_status, \ + .set_ioforce = ux500_pm_prcmu_set_ioforce, \ + } + +#define GPIO_RESOURCE(block) \ + { \ + .start = U8500_GPIOBANK##block##_BASE, \ + .end = U8500_GPIOBANK##block##_BASE + 127, \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = IRQ_DB8500_GPIO##block, \ + .end = IRQ_DB8500_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ + }, \ + { \ + .start = IRQ_PRCMU_GPIO##block, \ + .end = IRQ_PRCMU_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ + } + +#define GPIO_DEVICE(block) \ + { \ + .name = "gpio", \ + .id = block, \ + .num_resources = 3, \ + .resource = &u8500_gpio_resources[block * 3], \ + .dev = { \ + .platform_data = &u8500_gpio_data[block], \ + }, \ + } static struct nmk_gpio_platform_data u8500_gpio_data[] = { - GPIO_DATA("GPIO-0-31", 0), - GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */ - GPIO_DATA("GPIO-64-95", 64), - GPIO_DATA("GPIO-96-127", 96), /* 98..127 not routed to pin */ - GPIO_DATA("GPIO-128-159", 128), - GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */ - GPIO_DATA("GPIO-192-223", 192), - GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */ - GPIO_DATA("GPIO-256-288", 256), /* 268..288 not routed to pin */ + GPIO_DATA("GPIO-0-31", 0, 32), + GPIO_DATA("GPIO-32-63", 32, 5), /* 37..63 not routed to pin */ + GPIO_DATA("GPIO-64-95", 64, 32), + GPIO_DATA("GPIO-96-127", 96, 2), /* 98..127 not routed to pin */ + GPIO_DATA("GPIO-128-159", 128, 32), + GPIO_DATA("GPIO-160-191", 160, 12), /* 172..191 not routed to pin */ + GPIO_DATA("GPIO-192-223", 192, 32), + GPIO_DATA("GPIO-224-255", 224, 7), /* 231..255 not routed to pin */ + GPIO_DATA("GPIO-256-288", 256, 12), /* 268..288 not routed to pin */ }; static struct resource u8500_gpio_resources[] = { @@ -55,162 +109,475 @@ struct platform_device u8500_gpio_devs[] = { GPIO_DEVICE(8), }; -struct amba_device u8500_ssp0_device = { +static struct resource u8500_shrm_resources[] = { + [0] = { + .start = U8500_SHRM_GOP_INTERRUPT_BASE, + .end = U8500_SHRM_GOP_INTERRUPT_BASE + ((4*4)-1), + .name = "shrm_gop_register_base", + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CA_WAKE_REQ_V1, + .end = IRQ_CA_WAKE_REQ_V1, + .name = "ca_irq_wake_req", + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_AC_READ_NOTIFICATION_0_V1, + .end = IRQ_AC_READ_NOTIFICATION_0_V1, + .name = "ac_read_notification_0_irq", + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = IRQ_AC_READ_NOTIFICATION_1_V1, + .end = IRQ_AC_READ_NOTIFICATION_1_V1, + .name = "ac_read_notification_1_irq", + .flags = IORESOURCE_IRQ, + }, + [4] = { + .start = IRQ_CA_MSG_PEND_NOTIFICATION_0_V1, + .end = IRQ_CA_MSG_PEND_NOTIFICATION_0_V1, + .name = "ca_msg_pending_notification_0_irq", + .flags = IORESOURCE_IRQ, + }, + [5] = { + .start = IRQ_CA_MSG_PEND_NOTIFICATION_1_V1, + .end = IRQ_CA_MSG_PEND_NOTIFICATION_1_V1, + .name = "ca_msg_pending_notification_1_irq", + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device u8500_shrm_device = { + .name = "u8500_shrm", + .id = 0, .dev = { + .init_name = "shrm_bus", .coherent_dma_mask = ~0, - .init_name = "ssp0", - }, - .res = { - .start = U8500_SSP0_BASE, - .end = U8500_SSP0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, }, - .irq = {IRQ_SSP0, NO_IRQ }, - /* ST-Ericsson modified id */ - .periphid = SSP_PER_ID, + + .num_resources = ARRAY_SIZE(u8500_shrm_resources), + .resource = u8500_shrm_resources }; -static struct resource u8500_i2c0_resources[] = { +static struct resource mcde_resources[] = { [0] = { - .start = U8500_I2C0_BASE, - .end = U8500_I2C0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, + .name = MCDE_IO_AREA, + .start = U8500_MCDE_BASE, + .end = U8500_MCDE_BASE + U8500_MCDE_SIZE - 1, + .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_I2C0, - .end = IRQ_I2C0, - .flags = IORESOURCE_IRQ, - } + .name = MCDE_IO_AREA, + .start = U8500_DSI_LINK1_BASE, + .end = U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = MCDE_IO_AREA, + .start = U8500_DSI_LINK2_BASE, + .end = U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [3] = { + .name = MCDE_IO_AREA, + .start = U8500_DSI_LINK3_BASE, + .end = U8500_DSI_LINK3_BASE + U8500_DSI_LINK_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [4] = { + .name = MCDE_IRQ, + .start = IRQ_DB8500_DISP, + .end = IRQ_DB8500_DISP, + .flags = IORESOURCE_IRQ, + }, }; -struct platform_device u8500_i2c0_device = { - .name = "nmk-i2c", - .id = 0, - .resource = u8500_i2c0_resources, - .num_resources = ARRAY_SIZE(u8500_i2c0_resources), +static int mcde_platform_enable_dsipll(void) +{ + return prcmu_enable_dsipll(); +} + +static int mcde_platform_disable_dsipll(void) +{ + return prcmu_disable_dsipll(); +} + +static int mcde_platform_set_display_clocks(void) +{ + return prcmu_set_display_clocks(); +} + +static struct mcde_platform_data mcde_pdata = { + .num_dsilinks = 3, + /* + * [0] = 3: 24 bits DPI: connect LSB Ch B to D[0:7] + * [3] = 4: 24 bits DPI: connect MID Ch B to D[24:31] + * [4] = 5: 24 bits DPI: connect MSB Ch B to D[32:39] + * + * [1] = 3: TV out : connect LSB Ch B to D[8:15] + */ +#define DONT_CARE 0 + .outmux = { 3, 3, DONT_CARE, 4, 5 }, +#undef DONT_CARE + .syncmux = 0x00, /* DPI channel A and B on output pins A and B resp */ + .num_channels = 4, + .num_overlays = 6, + .regulator_vana_id = "v-ana", + .regulator_mcde_epod_id = "vsupply", + .regulator_esram_epod_id = "v-esram34", + .clock_dsi_id = "hdmi", + .clock_dsi_lp_id = "tv", + .clock_dpi_id = "lcd", + .clock_mcde_id = "mcde", + .platform_set_clocks = mcde_platform_set_display_clocks, + .platform_enable_dsipll = mcde_platform_enable_dsipll, + .platform_disable_dsipll = mcde_platform_disable_dsipll, }; -static struct resource u8500_i2c4_resources[] = { +struct platform_device ux500_mcde_device = { + .name = "mcde", + .id = -1, + .dev = { + .platform_data = &mcde_pdata, + }, + .num_resources = ARRAY_SIZE(mcde_resources), + .resource = mcde_resources, +}; + +static struct resource b2r2_resources[] = { [0] = { - .start = U8500_I2C4_BASE, - .end = U8500_I2C4_BASE + SZ_4K - 1, + .start = U8500_B2R2_BASE, + .end = U8500_B2R2_BASE + ((4*1024)-1), + .name = "b2r2_base", .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_I2C4, - .end = IRQ_I2C4, - .flags = IORESOURCE_IRQ, - } + .name = "B2R2_IRQ", + .start = IRQ_DB8500_B2R2, + .end = IRQ_DB8500_B2R2, + .flags = IORESOURCE_IRQ, + }, }; -struct platform_device u8500_i2c4_device = { - .name = "nmk-i2c", - .id = 4, - .resource = u8500_i2c4_resources, - .num_resources = ARRAY_SIZE(u8500_i2c4_resources), +struct platform_device ux500_b2r2_device = { + .name = "b2r2", + .id = 0, + .dev = { + .init_name = "b2r2_bus", + .coherent_dma_mask = ~0, + }, + .num_resources = ARRAY_SIZE(b2r2_resources), + .resource = b2r2_resources, }; -static struct resource dma40_resources[] = { +/* + * WATCHDOG + */ + +static struct resource ux500_wdt_resources[] = { [0] = { - .start = U8500_DMA_BASE, - .end = U8500_DMA_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - .name = "base", + .start = U8500_TWD_BASE, + .end = U8500_TWD_BASE+0x37, + .flags = IORESOURCE_MEM, }, [1] = { - .start = U8500_DMA_LCPA_BASE, - .end = U8500_DMA_LCPA_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - .name = "lcpa", - }, - [2] = { - .start = U8500_DMA_LCLA_BASE, - .end = U8500_DMA_LCLA_BASE + 16 * 1024 - 1, - .flags = IORESOURCE_MEM, - .name = "lcla", - }, - [3] = { - .start = IRQ_DMA, - .end = IRQ_DMA, - .flags = IORESOURCE_IRQ} + .start = IRQ_LOCALWDOG, + .end = IRQ_LOCALWDOG, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device ux500_wdt_device = { + .name = "mpcore_wdt", + .id = -1, + .resource = ux500_wdt_resources, + .num_resources = ARRAY_SIZE(ux500_wdt_resources), }; -/* Default configuration for physcial memcpy */ -struct stedma40_chan_cfg dma40_memcpy_conf_phy = { - .channel_type = (STEDMA40_CHANNEL_IN_PHY_MODE | - STEDMA40_LOW_PRIORITY_CHANNEL | - STEDMA40_PCHAN_BASIC_MODE), - .dir = STEDMA40_MEM_TO_MEM, +/* + * HSI + */ +#define HSIR_OVERRUN(num) { \ + .start = IRQ_DB8500_HSIR_CH##num##_OVRRUN, \ + .end = IRQ_DB8500_HSIR_CH##num##_OVRRUN, \ + .flags = IORESOURCE_IRQ, \ + .name = "hsi_rx_overrun_ch"#num \ +} - .src_info.endianess = STEDMA40_LITTLE_ENDIAN, - .src_info.data_width = STEDMA40_BYTE_WIDTH, - .src_info.psize = STEDMA40_PSIZE_PHY_1, +#define STE_HSI_PORT0_TX_CHANNEL_CFG(n) { \ + .dir = STEDMA40_MEM_TO_PERIPH, \ + .high_priority = false, \ + .mode = STEDMA40_MODE_LOGICAL, \ + .mode_opt = STEDMA40_LCHAN_SRC_LOG_DST_LOG, \ + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, \ + .dst_dev_type = n,\ + .src_info.big_endian = false,\ + .src_info.data_width = STEDMA40_WORD_WIDTH,\ + .dst_info.big_endian = false,\ + .dst_info.data_width = STEDMA40_WORD_WIDTH,\ +}, - .dst_info.endianess = STEDMA40_LITTLE_ENDIAN, - .dst_info.data_width = STEDMA40_BYTE_WIDTH, - .dst_info.psize = STEDMA40_PSIZE_PHY_1, +#define STE_HSI_PORT0_RX_CHANNEL_CFG(n) { \ + .dir = STEDMA40_PERIPH_TO_MEM, \ + .high_priority = false, \ + .mode = STEDMA40_MODE_LOGICAL, \ + .mode_opt = STEDMA40_LCHAN_SRC_LOG_DST_LOG, \ + .src_dev_type = n,\ + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, \ + .src_info.big_endian = false,\ + .src_info.data_width = STEDMA40_WORD_WIDTH,\ + .dst_info.big_endian = false,\ + .dst_info.data_width = STEDMA40_WORD_WIDTH,\ +}, +static struct resource u8500_hsi_resources[] = { + { + .start = U8500_HSIR_BASE, + .end = U8500_HSIR_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + .name = "hsi_rx_base" + }, + { + .start = U8500_HSIT_BASE, + .end = U8500_HSIT_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + .name = "hsi_tx_base" + }, + { + .start = IRQ_DB8500_HSIRD0, + .end = IRQ_DB8500_HSIRD0, + .flags = IORESOURCE_IRQ, + .name = "hsi_rx_irq0" + }, + { + .start = IRQ_DB8500_HSITD0, + .end = IRQ_DB8500_HSITD0, + .flags = IORESOURCE_IRQ, + .name = "hsi_tx_irq0" + }, + { + .start = IRQ_DB8500_HSIR_EXCEP, + .end = IRQ_DB8500_HSIR_EXCEP, + .flags = IORESOURCE_IRQ, + .name = "hsi_rx_excep0" + }, + HSIR_OVERRUN(0), + HSIR_OVERRUN(1), + HSIR_OVERRUN(2), + HSIR_OVERRUN(3), + HSIR_OVERRUN(4), + HSIR_OVERRUN(5), + HSIR_OVERRUN(6), + HSIR_OVERRUN(7), }; -/* Default configuration for logical memcpy */ -struct stedma40_chan_cfg dma40_memcpy_conf_log = { - .channel_type = (STEDMA40_CHANNEL_IN_LOG_MODE | - STEDMA40_LOW_PRIORITY_CHANNEL | - STEDMA40_LCHAN_SRC_LOG_DST_LOG | - STEDMA40_NO_TIM_FOR_LINK), - .dir = STEDMA40_MEM_TO_MEM, - .src_info.endianess = STEDMA40_LITTLE_ENDIAN, - .src_info.data_width = STEDMA40_BYTE_WIDTH, - .src_info.psize = STEDMA40_PSIZE_LOG_1, +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg ste_hsi_port0_dma_tx_cfg[] = { + STE_HSI_PORT0_TX_CHANNEL_CFG(DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0) + STE_HSI_PORT0_TX_CHANNEL_CFG(DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1) + STE_HSI_PORT0_TX_CHANNEL_CFG(DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2) + STE_HSI_PORT0_TX_CHANNEL_CFG(DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3) +}; - .dst_info.endianess = STEDMA40_LITTLE_ENDIAN, - .dst_info.data_width = STEDMA40_BYTE_WIDTH, - .dst_info.psize = STEDMA40_PSIZE_LOG_1, +static struct stedma40_chan_cfg ste_hsi_port0_dma_rx_cfg[] = { + STE_HSI_PORT0_RX_CHANNEL_CFG(DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0) + STE_HSI_PORT0_RX_CHANNEL_CFG(DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1) + STE_HSI_PORT0_RX_CHANNEL_CFG(DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2) + STE_HSI_PORT0_RX_CHANNEL_CFG(DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3) +}; +#endif +static struct ste_hsi_port_cfg ste_hsi_port0_cfg = { +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_tx_cfg = ste_hsi_port0_dma_tx_cfg, + .dma_rx_cfg = ste_hsi_port0_dma_rx_cfg +#endif +}; + +struct ste_hsi_platform_data u8500_hsi_platform_data = { + .num_ports = 1, + .use_dma = 1, + .port_cfg = &ste_hsi_port0_cfg, +}; + +struct platform_device u8500_hsi_device = { + .dev = { + .platform_data = &u8500_hsi_platform_data, + }, + .name = "ste_hsi", + .id = 0, + .resource = u8500_hsi_resources, + .num_resources = ARRAY_SIZE(u8500_hsi_resources) }; /* - * Mapping between destination event lines and physical device address. - * The event line is tied to a device and therefor the address is constant. + * Thermal Sensor */ -static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV]; -/* Mapping between source event lines and physical device address */ -static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV]; +static struct resource u8500_thsens_resources[] = { + { + .name = "IRQ_HOTMON_LOW", + .start = IRQ_PRCMU_HOTMON_LOW, + .end = IRQ_PRCMU_HOTMON_LOW, + .flags = IORESOURCE_IRQ, + }, + { + .name = "IRQ_HOTMON_HIGH", + .start = IRQ_PRCMU_HOTMON_HIGH, + .end = IRQ_PRCMU_HOTMON_HIGH, + .flags = IORESOURCE_IRQ, + }, +}; -/* Reserved event lines for memcpy only */ -static int dma40_memcpy_event[] = { - STEDMA40_MEMCPY_TX_1, - STEDMA40_MEMCPY_TX_2, - STEDMA40_MEMCPY_TX_3, - STEDMA40_MEMCPY_TX_4, +struct platform_device u8500_thsens_device = { + .name = "db8500_temp", + .resource = u8500_thsens_resources, + .num_resources = ARRAY_SIZE(u8500_thsens_resources), }; -static struct stedma40_platform_data dma40_plat_data = { - .dev_len = STEDMA40_NR_DEV, - .dev_rx = dma40_rx_map, - .dev_tx = dma40_tx_map, - .memcpy = dma40_memcpy_event, - .memcpy_len = ARRAY_SIZE(dma40_memcpy_event), - .memcpy_conf_phy = &dma40_memcpy_conf_phy, - .memcpy_conf_log = &dma40_memcpy_conf_log, - .llis_per_log = 8, +#ifdef CONFIG_STM_TRACE +static pin_cfg_t mop500_stm_mipi34_pins[] = { + GPIO70_STMAPE_CLK | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO71_STMAPE_DAT3 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO72_STMAPE_DAT2 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO73_STMAPE_DAT1 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO74_STMAPE_DAT0 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO75_U2_RXD | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO76_U2_TXD | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, }; -struct platform_device u8500_dma40_device = { - .dev = { - .platform_data = &dma40_plat_data, - }, - .name = "dma40", - .id = 0, - .num_resources = ARRAY_SIZE(dma40_resources), - .resource = dma40_resources +static pin_cfg_t mop500_stm_mipi60_pins[] = { + GPIO153_U2_RXD, + GPIO154_U2_TXD, + GPIO155_STMAPE_CLK, + GPIO156_STMAPE_DAT3, + GPIO157_STMAPE_DAT2, + GPIO158_STMAPE_DAT1, + GPIO159_STMAPE_DAT0, +}; + +static pin_cfg_t mop500_ske_pins[] = { + GPIO153_KP_I7, + GPIO154_KP_I6, + GPIO155_KP_I5, + GPIO156_KP_I4, + GPIO157_KP_O7, + GPIO158_KP_O6, + GPIO159_KP_O5, }; -void dma40_u8500ed_fixup(void) +/* + * Disable Trace of modem on MIPI34 and MIPI60 probe 2 + * ie disable ALT-C3 on GPIO70-76 + */ +static void stm_disable_modem_on_mipi34(void) +{ + u32 gpiocr; + + gpiocr = readl(PRCM_GPIOCR); + /* Disable altC3 on GPIO70-74 (STMMOD) */ + gpiocr &= ~PRCM_GPIOCR_DBG_STM_MOD_CMD1; + /* Disable altC3 on GPIO75-76 (UARTMOD) (?) */ + gpiocr &= ~PRCM_GPIOCR_DBG_UARTMOD_CMD0; + writel(gpiocr, PRCM_GPIOCR); +} + +/* + * Enable Trace of modem on MIPI34 and MIPI60 probe 2 + * ie enable ALT-C3 on GPIO70-76 + */ +static void stm_enable_modem_on_mipi34(void) +{ + u32 gpiocr; + + gpiocr = readl(PRCM_GPIOCR); + /* Enable altC3 on GPIO70-74 (STMMOD) and GPIO75-76 (UARTMOD) */ + gpiocr |= (PRCM_GPIOCR_DBG_STM_MOD_CMD1 | PRCM_GPIOCR_DBG_UARTMOD_CMD0); + writel(gpiocr, PRCM_GPIOCR); +} + +static int stm_enable_mipi34(void) +{ + int retval; + + retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); + if (retval) + pr_err("STM: Failed to enable MIPI34"); + return retval; +} + +static int stm_disable_mipi34(void) { - dma40_plat_data.memcpy = NULL; - dma40_plat_data.memcpy_len = 0; - dma40_resources[0].start = U8500_DMA_BASE_ED; - dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1; + int retval; + + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); + if (retval) + pr_err("STM: Failed to disable MIPI34"); + return retval; } + +static int stm_enable_ape_modem_mipi60(void) +{ + int retval; + + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_ske_pins)); + if (retval) + pr_err("STM: Failed to disable SKE GPIO"); + else { + retval = + nmk_config_pins(ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); + if (retval) + pr_err("STM: Failed to enable MIPI60"); + } + return retval; +} + +static int stm_disable_ape_modem_mipi60(void) +{ + int retval; + + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); + if (retval) + pr_err("STM: Failed to disable MIPI60"); + else { + retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_ske_pins)); + if (retval) + pr_err("STM: Failed to enable SKE gpio"); + } + return retval; +} + +static struct stm_platform_data stm_pdata = { + .regs_phys_base = U8500_STM_REG_BASE, + .channels_phys_base = U8500_STM_BASE, + .periph_id = 0xEC0D3800, /* or 0xEC0D2800 for 8500V1 */ + .cell_id = 0x0DF005B1, + /* + * These are the channels used by NMF and some external softwares + * expect the NMF traces to be output on these channels + * For legacy reason, we need to reserve them. + * NMF channels reserved resp MPCEE (100), CM (101) & HOSTEE (151) + */ + .channels_reserved = {100, 101, 151, -1}, + /* Enable all except MCSBAG */ + .masters_enabled = STM_ENABLE_ARM | STM_ENABLE_SVA | + STM_ENABLE_PRCMU | STM_ENABLE_SIA | STM_ENABLE_SIA_XP70, + .ste_enable_modem_on_mipi34 = stm_enable_modem_on_mipi34, + .ste_disable_modem_on_mipi34 = stm_disable_modem_on_mipi34, + .ste_gpio_enable_mipi34 = stm_enable_mipi34, + .ste_gpio_disable_mipi34 = stm_disable_mipi34, + .ste_gpio_enable_ape_modem_mipi60 = stm_enable_ape_modem_mipi60, + .ste_gpio_disable_ape_modem_mipi60 = stm_disable_ape_modem_mipi60, +}; + +struct platform_device ux500_stm_device = { + .name = "stm", + .id = -1, + .dev = { + .platform_data = &stm_pdata, + }, +}; +#endif /* CONFIG_STM_TRACE */ + diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h new file mode 100644 index 00000000000..1f997703e70 --- /dev/null +++ b/arch/arm/mach-ux500/devices-db8500.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_DB8500_H +#define __DEVICES_DB8500_H + +#include "devices-common.h" + +struct ske_keypad_platform_data; +struct pl022_ssp_controller; + +static inline struct platform_device * +db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata) +{ + return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1, + U8500_SKE_BASE, + IRQ_DB8500_KB, pdata); +} + +static inline struct amba_device * +db8500_add_ssp(const char *name, resource_size_t base, int irq, + struct pl022_ssp_controller *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0, NULL); +} + + +#define db8500_add_i2c0(pdata) \ + dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata) +#define db8500_add_i2c1(pdata) \ + dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata) +#define db8500_add_i2c2(pdata) \ + dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata) +#define db8500_add_i2c3(pdata) \ + dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata) +#define db8500_add_i2c4(pdata) \ + dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata) + +#define db8500_add_msp0_i2s(pdata) \ + dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_i2s(pdata) \ + dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_i2s(pdata) \ + dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_i2s(pdata) \ + dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) + +#define db8500_add_msp0_spi(pdata) \ + dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_spi(pdata) \ + dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_spi(pdata) \ + dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_spi(pdata) \ + dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) + +#define db8500_add_rtc() \ + dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC); + +#define db8500_add_sdi0(pdata) \ + dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata) +#define db8500_add_sdi1(pdata) \ + dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata) +#define db8500_add_sdi2(pdata) \ + dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata) +#define db8500_add_sdi3(pdata) \ + dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata) +#define db8500_add_sdi4(pdata) \ + dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata) +#define db8500_add_sdi5(pdata) \ + dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata) + +#define db8500_add_ssp0(pdata) \ + db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata) +#define db8500_add_ssp1(pdata) \ + db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata) + +#define db8500_add_spi0(pdata) \ + dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata) +#define db8500_add_spi1(pdata) \ + dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata) +#define db8500_add_spi2(pdata) \ + dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata) +#define db8500_add_spi3(pdata) \ + dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata) + +#define db8500_add_uart0(pdata) \ + dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata) +#define db8500_add_uart1() \ + dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, NULL) +#define db8500_add_uart2() \ + dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, NULL) + +#endif diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c index 8a268893cb7..54d791d95c1 100644 --- a/arch/arm/mach-ux500/devices.c +++ b/arch/arm/mach-ux500/devices.c @@ -7,75 +7,258 @@ #include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/sysdev.h> +#include <linux/amba/bus.h> +#include <linux/amba/serial.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/gpio.h> +#include <linux/usb/musb.h> #include <linux/amba/bus.h> +#include <linux/dma-mapping.h> +#ifdef CONFIG_ANDROID_PMEM +#include <linux/android_pmem.h> +#endif + +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/setup.h> +#include <mach/crypto-ux500.h> +#include <mach/irqs.h> #include <mach/hardware.h> +#include <mach/devices.h> #include <mach/setup.h> -#define __MEM_4K_RESOURCE(x) \ - .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} +#include <plat/ste_dma40.h> + +#ifdef CONFIG_STE_TRACE_MODEM +#include <linux/db8500-modem-trace.h> +#endif + +#ifdef CONFIG_STE_TRACE_MODEM +static struct resource trace_resource = { + .start = 0, + .end = 0, + .name = "db8500-trace-area", + .flags = IORESOURCE_MEM +}; + +static struct db8500_trace_platform_data trace_pdata = { + .ape_base = U8500_APE_BASE, + .modem_base = U8500_MODEM_BASE, +}; -struct amba_device ux500_pl031_device = { +struct platform_device u8500_trace_modem = { + .name = "db8500-modem-trace", + .id = 0, .dev = { - .init_name = "pl031", - }, - .res = { - .start = UX500_RTC_BASE, - .end = UX500_RTC_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, + .init_name = "db8500-modem-trace", + .platform_data = &trace_pdata, }, - .irq = {IRQ_RTC_RTT, NO_IRQ}, + .num_resources = 1, + .resource = &trace_resource, }; -struct amba_device ux500_uart0_device = { - .dev = { .init_name = "uart0" }, - __MEM_4K_RESOURCE(UX500_UART0_BASE), - .irq = {IRQ_UART0, NO_IRQ}, -}; +static int __init early_trace_modem(char *p) +{ + struct resource *data = &trace_resource; + u32 size = memparse(p, &p); + + if (*p == '@') + data->start = memparse(p + 1, &p); + data->end = data->start + size; + + return 0; +} + +early_param("mem_mtrace", early_trace_modem); +#endif -struct amba_device ux500_uart1_device = { - .dev = { .init_name = "uart1" }, - __MEM_4K_RESOURCE(UX500_UART1_BASE), - .irq = {IRQ_UART1, NO_IRQ}, +#ifdef CONFIG_HWMEM +struct platform_device ux500_hwmem_device = { + .name = "hwmem", }; +#endif + +#ifdef CONFIG_ANDROID_PMEM +static int __init early_pmem_generic_parse(char *p, + struct android_pmem_platform_data * data) +{ + data->size = memparse(p, &p); + if (*p == '@') + data->start = memparse(p + 1, &p); -struct amba_device ux500_uart2_device = { - .dev = { .init_name = "uart2" }, - __MEM_4K_RESOURCE(UX500_UART2_BASE), - .irq = {IRQ_UART2, NO_IRQ}, + return 0; +} + +/* + * Pmem device used by surface flinger + */ +static struct android_pmem_platform_data pmem_pdata = { + .name = "pmem", + .no_allocator = 1, /* MemoryHeapBase is having an allocator */ + .cached = 1, + .start = 0, + .size = 0, }; -#define UX500_I2C_RESOURCES(id, size) \ -static struct resource ux500_i2c##id##_resources[] = { \ - [0] = { \ - .start = UX500_I2C##id##_BASE, \ - .end = UX500_I2C##id##_BASE + size - 1, \ - .flags = IORESOURCE_MEM, \ - }, \ - [1] = { \ - .start = IRQ_I2C##id, \ - .end = IRQ_I2C##id, \ - .flags = IORESOURCE_IRQ \ - } \ +static int __init early_pmem(char *p) +{ + return early_pmem_generic_parse(p, &pmem_pdata); } +early_param("pmem", early_pmem); + +struct platform_device u8500_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { + .platform_data = &pmem_pdata, + }, +}; -UX500_I2C_RESOURCES(1, SZ_4K); -UX500_I2C_RESOURCES(2, SZ_4K); -UX500_I2C_RESOURCES(3, SZ_4K); +/* + * Pmem device used by OMX components allocating buffers + */ +static struct android_pmem_platform_data pmem_hwb_pdata = { + .name = "pmem_hwb", + .no_allocator = 1, /* We'll manage allocation */ + .cached = 1, + .start = 0, + .size = 0, +}; -#define UX500_I2C_PDEVICE(cid) \ -struct platform_device ux500_i2c##cid##_device = { \ - .name = "nmk-i2c", \ - .id = cid, \ - .num_resources = 2, \ - .resource = ux500_i2c##cid##_resources, \ +static int __init early_pmem_hwb(char *p) +{ + return early_pmem_generic_parse(p, &pmem_hwb_pdata); } +early_param("pmem_hwb", early_pmem_hwb); -UX500_I2C_PDEVICE(1); -UX500_I2C_PDEVICE(2); -UX500_I2C_PDEVICE(3); +struct platform_device u8500_pmem_hwb_device = { + .name = "android_pmem", + .id = 2, + .dev = { + .platform_data = &pmem_hwb_pdata, + }, +}; +#endif + +#ifdef CONFIG_CRYPTO_DEV_UX500_HASH +static struct resource ux500_hash1_resources[] = { + [0] = { + .start = U8500_HASH1_BASE, + .end = U8500_HASH1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + } +}; + +struct platform_device ux500_hash1_device = { + .name = "hash1", + .id = -1, + .num_resources = 1, + .resource = ux500_hash1_resources +}; +#endif + +static struct resource ux500_cryp1_resources[] = { + [0] = { + .start = U8500_CRYP1_BASE, + .end = U8500_CRYP1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_DB8500_CRYP1, + .end = IRQ_DB8500_CRYP1, + .flags = IORESOURCE_IRQ + } +}; + +static struct cryp_platform_data cryp1_platform_data = { + .mem_to_engine = { + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV48_CAC1_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, + .mode = STEDMA40_MODE_LOGICAL, + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + }, + .engine_to_mem = { + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV48_CAC1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, + .mode = STEDMA40_MODE_LOGICAL, + .src_info.psize = STEDMA40_PSIZE_LOG_4, + .dst_info.psize = STEDMA40_PSIZE_LOG_4, + } +}; + +struct platform_device ux500_cryp1_device = { + .name = "cryp1", + .id = -1, + .dev = { + .platform_data = &cryp1_platform_data + }, + .num_resources = ARRAY_SIZE(ux500_cryp1_resources), + .resource = ux500_cryp1_resources +}; + +#if defined(CONFIG_USB_MUSB_HOST) +#define MUSB_MODE MUSB_HOST +#elif defined(CONFIG_USB_MUSB_PERIPHERAL) +#define MUSB_MODE MUSB_PERIPHERAL +#elif defined(CONFIG_USB_MUSB_OTG) +#define MUSB_MODE MUSB_OTG +#else +#define MUSB_MODE MUSB_UNDEFINED +#endif +static struct musb_hdrc_config musb_hdrc_hs_otg_config = { + .multipoint = true, /* multipoint device */ + .dyn_fifo = true, /* supports dynamic fifo sizing */ + .num_eps = 16, /* number of endpoints _with_ ep0 */ + .ram_bits = 16, /* ram address size */ +}; + +static struct musb_hdrc_platform_data musb_hdrc_hs_otg_platform_data = { + .mode = MUSB_MODE, + .clock = "usb", /* for clk_get() */ + .config = &musb_hdrc_hs_otg_config, +}; + +static struct resource usb_resources[] = { + [0] = { + .name = "usb-mem", + .start = U8500_USBOTG_BASE, + .end = (U8500_USBOTG_BASE + SZ_64K - 1), + .flags = IORESOURCE_MEM, + }, + + [1] = { + .name = "usb-irq", + .start = IRQ_DB8500_USBOTG, + .end = IRQ_DB8500_USBOTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 musb_dmamask = DMA_BIT_MASK(32); + +struct platform_device ux500_musb_device = { + .name = "musb_hdrc", + .id = 0, + .dev = { + .init_name = "musb_hdrc.0", /* for clk_get() */ + .platform_data = &musb_hdrc_hs_otg_platform_data, + .dma_mask = &musb_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32) + }, + .num_resources = ARRAY_SIZE(usb_resources), + .resource = usb_resources, +}; void __init amba_add_devices(struct amba_device *devs[], int num) { diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c new file mode 100644 index 00000000000..d4ef1b5fa3b --- /dev/null +++ b/arch/arm/mach-ux500/dma-db5500.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <plat/ste_dma40.h> +#include <mach/setup.h> +#include <mach/ste-dma40-db5500.h> + +static struct resource dma40_resources[] = { + [0] = { + .start = U5500_DMA_BASE, + .end = U5500_DMA_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + .name = "base", + }, + [1] = { + .start = U5500_DMA_LCPA_BASE, + .end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1, + .flags = IORESOURCE_MEM, + .name = "lcpa", + }, + [2] = { + .start = IRQ_DB5500_DMA, + .end = IRQ_DB5500_DMA, + .flags = IORESOURCE_IRQ + } +}; + +/* Default configuration for physical memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_phy = { + .mode = STEDMA40_MODE_PHYSICAL, + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_PHY_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_PHY_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, +}; + +/* Default configuration for logical memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_log = { + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_LOG_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_LOG_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, +}; + +/* + * Mapping between soruce event lines and physical device address This was + * created assuming that the event line is tied to a device and therefore the + * address is constant, however this is not true for at least USB, and the + * values are just placeholders for USB. This table is preserved and used for + * now. + */ +static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = { + [DB5500_DMA_DEV0_SPI0_RX] = 0, + [DB5500_DMA_DEV1_SPI1_RX] = 0, + [DB5500_DMA_DEV2_SPI2_RX] = 0, + [DB5500_DMA_DEV3_SPI3_RX] = 0, + [DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV7_IRDA_RFS] = 0, + [DB5500_DMA_DEV8_IRDA_FIFO_RX] = 0, + [DB5500_DMA_DEV9_MSP0_RX] = U5500_MSP0_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV10_MSP1_RX] = U5500_MSP1_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV11_MSP2_RX] = U5500_MSP2_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV12_UART0_RX] = 0, + [DB5500_DMA_DEV13_UART1_RX] = 0, + [DB5500_DMA_DEV14_UART2_RX] = 0, + [DB5500_DMA_DEV15_UART3_RX] = 0, + [DB5500_DMA_DEV16_USB_OTG_IEP_8] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV17_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV18_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV19_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV24_SDMMC0_RX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV25_SDMMC1_RX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV26_SDMMC2_RX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV27_SDMMC3_RX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV28_SDMMC4_RX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + /* 29 - 32 not used */ + [DB5500_DMA_DEV33_SDMMC0_RX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV34_SDMMC1_RX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV35_SDMMC2_RX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV36_SDMMC3_RX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV37_SDMMC4_RX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV38_USB_OTG_IEP_8] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV39_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV40_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV41_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV42_USB_OTG_IEP_4_12] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV43_USB_OTG_IEP_5_13] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV44_USB_OTG_IEP_6_14] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV45_USB_OTG_IEP_7_15] = U5500_USBOTG_BASE, + /* 46 not used */ + [DB5500_DMA_DEV47_MCDE_RX] = 0, + [DB5500_DMA_DEV48_CRYPTO1_RX] = 0, + /* 49, 50 not used */ + [DB5500_DMA_DEV49_I2C1_RX] = 0, + [DB5500_DMA_DEV50_I2C3_RX] = 0, + [DB5500_DMA_DEV51_I2C2_RX] = 0, + /* 54 - 60 not used */ + [DB5500_DMA_DEV61_CRYPTO0_RX] = 0, + /* 62, 63 not used */ +}; + +/* Mapping between destination event lines and physical device address */ +static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = { + [DB5500_DMA_DEV0_SPI0_TX] = 0, + [DB5500_DMA_DEV1_SPI1_TX] = 0, + [DB5500_DMA_DEV2_SPI2_TX] = 0, + [DB5500_DMA_DEV3_SPI3_TX] = 0, + [DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV7_IRRC_TX] = 0, + [DB5500_DMA_DEV8_IRDA_FIFO_TX] = 0, + [DB5500_DMA_DEV9_MSP0_TX] = U5500_MSP0_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV10_MSP1_TX] = U5500_MSP1_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV11_MSP2_TX] = U5500_MSP2_BASE + MSP_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV12_UART0_TX] = 0, + [DB5500_DMA_DEV13_UART1_TX] = 0, + [DB5500_DMA_DEV14_UART2_TX] = 0, + [DB5500_DMA_DEV15_UART3_TX] = 0, + [DB5500_DMA_DEV16_USB_OTG_OEP_8] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV17_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV18_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV19_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV24_SDMMC0_TX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV25_SDMMC1_TX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV26_SDMMC2_TX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV27_SDMMC3_TX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV28_SDMMC4_TX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + /* 29 - 31 not used */ + [DB5500_DMA_DEV32_FSMC_TX] = 0, + [DB5500_DMA_DEV33_SDMMC0_TX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV34_SDMMC1_TX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV35_SDMMC2_TX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV36_SDMMC3_TX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV37_SDMMC4_TX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB5500_DMA_DEV38_USB_OTG_OEP_8] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV39_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV40_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV41_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV42_USB_OTG_OEP_4_12] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV43_USB_OTG_OEP_5_13] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV44_USB_OTG_OEP_6_14] = U5500_USBOTG_BASE, + [DB5500_DMA_DEV45_USB_OTG_OEP_7_15] = U5500_USBOTG_BASE, + /* 46 not used */ + [DB5500_DMA_DEV47_STM_TX] = 0, + [DB5500_DMA_DEV48_CRYPTO1_TX] = 0, + [DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX] = 0, + [DB5500_DMA_DEV50_HASH1_TX] = 0, + [DB5500_DMA_DEV51_I2C1_TX] = 0, + [DB5500_DMA_DEV52_I2C3_TX] = 0, + [DB5500_DMA_DEV53_I2C2_TX] = 0, + /* 54, 55 not used */ + [DB5500_DMA_MEMCPY_TX_1] = 0, + [DB5500_DMA_MEMCPY_TX_2] = 0, + [DB5500_DMA_MEMCPY_TX_3] = 0, + [DB5500_DMA_MEMCPY_TX_4] = 0, + [DB5500_DMA_MEMCPY_TX_5] = 0, + [DB5500_DMA_DEV61_CRYPTO0_TX] = 0, + [DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX] = 0, + [DB5500_DMA_DEV63_HASH0_TX] = 0, +}; + +static int dma40_memcpy_event[] = { + DB5500_DMA_MEMCPY_TX_1, + DB5500_DMA_MEMCPY_TX_2, + DB5500_DMA_MEMCPY_TX_3, + DB5500_DMA_MEMCPY_TX_4, + DB5500_DMA_MEMCPY_TX_5, +}; + +static struct stedma40_platform_data dma40_plat_data = { + .dev_len = ARRAY_SIZE(dma40_rx_map), + .dev_rx = dma40_rx_map, + .dev_tx = dma40_tx_map, + .memcpy = dma40_memcpy_event, + .memcpy_len = ARRAY_SIZE(dma40_memcpy_event), + .memcpy_conf_phy = &dma40_memcpy_conf_phy, + .memcpy_conf_log = &dma40_memcpy_conf_log, + .disabled_channels = {-1}, +}; + +static struct platform_device dma40_device = { + .dev = { + .platform_data = &dma40_plat_data, + }, + .name = "dma40", + .id = 0, + .num_resources = ARRAY_SIZE(dma40_resources), + .resource = dma40_resources +}; + +void __init db5500_dma_init(void) +{ + int ret; + + ret = platform_device_register(&dma40_device); + if (ret) + dev_err(&dma40_device.dev, "unable to register device: %d\n", ret); + +} diff --git a/arch/arm/mach-ux500/dma-db8500.c b/arch/arm/mach-ux500/dma-db8500.c new file mode 100644 index 00000000000..f15fb2e48a0 --- /dev/null +++ b/arch/arm/mach-ux500/dma-db8500.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) ST-Ericsson SA 2007-2010 + * + * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <plat/ste_dma40.h> + +#include <mach/hsi.h> +#include <mach/setup.h> +#include <mach/ste-dma40-db8500.h> + +#include "pm/context.h" + +static struct resource dma40_resources[] = { + [0] = { + .start = U8500_DMA_BASE, + .end = U8500_DMA_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + .name = "base", + }, + [1] = { + .start = U8500_DMA_LCPA_BASE, + .end = U8500_DMA_LCPA_BASE + 2 * SZ_1K - 1, + .flags = IORESOURCE_MEM, + .name = "lcpa", + }, + [2] = { + .start = IRQ_DB8500_DMA, + .end = IRQ_DB8500_DMA, + .flags = IORESOURCE_IRQ + } +}; + +/* Default configuration for physcial memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_phy = { + .mode = STEDMA40_MODE_PHYSICAL, + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_PHY_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_PHY_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + +}; + +/* Default configuration for logical memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_log = { + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_LOG_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_LOG_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + +}; + +/* + * Mapping between soruce event lines and physical device address + * This was created assuming that the event line is tied to a device and + * therefore the address is constant, however this is not true for at least + * USB, and the values are just placeholders for USB. This table is preserved + * and used for now. + */ +static dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = { + [DB8500_DMA_DEV0_SPI0_RX] = 0, + [DB8500_DMA_DEV1_SD_MMC0_RX] = 0, + [DB8500_DMA_DEV2_SD_MMC1_RX] = 0, + [DB8500_DMA_DEV3_SD_MMC2_RX] = 0, + [DB8500_DMA_DEV4_I2C1_RX] = 0, + [DB8500_DMA_DEV5_I2C3_RX] = 0, + [DB8500_DMA_DEV6_I2C2_RX] = 0, + [DB8500_DMA_DEV7_I2C4_RX] = 0, + [DB8500_DMA_DEV8_SSP0_RX] = U8500_SSP0_BASE + SSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV9_SSP1_RX] = 0, + [DB8500_DMA_DEV10_MCDE_RX] = 0, + [DB8500_DMA_DEV11_UART2_RX] = 0, + [DB8500_DMA_DEV12_UART1_RX] = 0, + [DB8500_DMA_DEV13_UART0_RX] = 0, + [DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV15_I2C0_RX] = 0, + [DB8500_DMA_DEV16_USB_OTG_IEP_7_15] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV17_USB_OTG_IEP_6_14] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV18_USB_OTG_IEP_5_13] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV19_USB_OTG_IEP_4_12] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0] = U8500_HSIR_BASE + 0x0 + STE_HSI_RX_BUFFERX, + [DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1] = U8500_HSIR_BASE + 0x4 + STE_HSI_RX_BUFFERX, + [DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2] = U8500_HSIR_BASE + 0x8 + STE_HSI_RX_BUFFERX, + [DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3] = U8500_HSIR_BASE + 0xC + STE_HSI_RX_BUFFERX, + [DB8500_DMA_DEV24_SRC_SXA0_RX_TX] = 0, + [DB8500_DMA_DEV25_SRC_SXA1_RX_TX] = 0, + [DB8500_DMA_DEV26_SRC_SXA2_RX_TX] = 0, + [DB8500_DMA_DEV27_SRC_SXA3_RX_TX] = 0, + [DB8500_DMA_DEV28_SD_MM2_RX] = U8500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV29_SD_MM0_RX] = U8500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV30_MSP1_RX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV32_SD_MM1_RX] = U8500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV33_SPI2_RX] = 0, + [DB8500_DMA_DEV34_I2C3_RX2] = 0, + [DB8500_DMA_DEV35_SPI1_RX] = 0, + [DB8500_DMA_DEV36_USB_OTG_IEP_3_11] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV37_USB_OTG_IEP_2_10] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV38_USB_OTG_IEP_1_9] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV39_USB_OTG_IEP_8] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV40_SPI3_RX] = 0, + [DB8500_DMA_DEV41_SD_MM3_RX] = 0, + [DB8500_DMA_DEV42_SD_MM4_RX] = U8500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV43_SD_MM5_RX] = 0, + [DB8500_DMA_DEV44_SRC_SXA4_RX_TX] = 0, + [DB8500_DMA_DEV45_SRC_SXA5_RX_TX] = 0, + [DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX] = 0, + [DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX] = 0, + [DB8500_DMA_DEV48_CAC1_RX] = U8500_CRYP1_BASE + CRYP1_RX_REG_OFFSET, + /* 49, 50 and 51 are not used */ + [DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4] = 0, + [DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5] = 0, + [DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6] = 0, + [DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7] = 0, + /* 56, 57, 58, 59 and 60 are not used */ + [DB8500_DMA_DEV61_CAC0_RX] = 0, + /* 62 and 63 are not used */ +}; + +/* Mapping between destination event lines and physical device address */ +static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = { + [DB8500_DMA_DEV0_SPI0_TX] = 0, + [DB8500_DMA_DEV1_SD_MMC0_TX] = 0, + [DB8500_DMA_DEV2_SD_MMC1_TX] = 0, + [DB8500_DMA_DEV3_SD_MMC2_TX] = 0, + [DB8500_DMA_DEV4_I2C1_TX] = 0, + [DB8500_DMA_DEV5_I2C3_TX] = 0, + [DB8500_DMA_DEV6_I2C2_TX] = 0, + [DB8500_DMA_DEV7_I2C4_TX] = 0, + [DB8500_DMA_DEV8_SSP0_TX] = U8500_SSP0_BASE + SSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV9_SSP1_TX] = 0, + /* 10 is not used*/ + [DB8500_DMA_DEV11_UART2_TX] = 0, + [DB8500_DMA_DEV12_UART1_TX] = 0, + [DB8500_DMA_DEV13_UART0_TX] = 0, + [DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV15_I2C0_TX] = 0, + [DB8500_DMA_DEV16_USB_OTG_OEP_7_15] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV17_USB_OTG_OEP_6_14] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV18_USB_OTG_OEP_5_13] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV19_USB_OTG_OEP_4_12] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0] = U8500_HSIT_BASE + 0x0 + STE_HSI_TX_BUFFERX, + [DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1] = U8500_HSIT_BASE + 0x4 + STE_HSI_TX_BUFFERX, + [DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2] = U8500_HSIT_BASE + 0x8 + STE_HSI_TX_BUFFERX, + [DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3] = U8500_HSIT_BASE + 0xC + STE_HSI_TX_BUFFERX, + [DB8500_DMA_DEV24_DST_SXA0_RX_TX] = 0, + [DB8500_DMA_DEV25_DST_SXA1_RX_TX] = 0, + [DB8500_DMA_DEV26_DST_SXA2_RX_TX] = 0, + [DB8500_DMA_DEV27_DST_SXA3_RX_TX] = 0, + [DB8500_DMA_DEV28_SD_MM2_TX] = U8500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV29_SD_MM0_TX] = U8500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV32_SD_MM1_TX] = U8500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV33_SPI2_TX] = 0, + [DB8500_DMA_DEV34_I2C3_TX2] = 0, + [DB8500_DMA_DEV35_SPI1_TX] = 0, + [DB8500_DMA_DEV36_USB_OTG_OEP_3_11] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV37_USB_OTG_OEP_2_10] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV38_USB_OTG_OEP_1_9] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV39_USB_OTG_OEP_8] = U8500_USBOTG_BASE, + [DB8500_DMA_DEV40_SPI3_TX] = 0, + [DB8500_DMA_DEV41_SD_MM3_TX] = 0, + [DB8500_DMA_DEV42_SD_MM4_TX] = U8500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET, + [DB8500_DMA_DEV43_SD_MM5_TX] = 0, + [DB8500_DMA_DEV44_DST_SXA4_RX_TX] = 0, + [DB8500_DMA_DEV45_DST_SXA5_RX_TX] = 0, + [DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX] = 0, + [DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX] = 0, + [DB8500_DMA_DEV48_CAC1_TX] = U8500_CRYP1_BASE + CRYP1_TX_REG_OFFSET, + [DB8500_DMA_DEV49_CAC1_TX_HAC1_TX] = 0, + [DB8500_DMA_DEV50_HAC1_TX] = 0, + [DB8500_DMA_MEMCPY_TX_0] = 0, + [DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4] = 0, + [DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5] = 0, + [DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6] = 0, + [DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7] = 0, + [DB8500_DMA_MEMCPY_TX_1] = 0, + [DB8500_DMA_MEMCPY_TX_2] = 0, + [DB8500_DMA_MEMCPY_TX_3] = 0, + [DB8500_DMA_MEMCPY_TX_4] = 0, + [DB8500_DMA_MEMCPY_TX_5] = 0, + [DB8500_DMA_DEV61_CAC0_TX] = 0, + [DB8500_DMA_DEV62_CAC0_TX_HAC0_TX] = 0, + [DB8500_DMA_DEV63_HAC0_TX] = 0, +}; + +/* Reserved event lines for memcpy only */ +static int dma40_memcpy_event[] = { + DB8500_DMA_MEMCPY_TX_0, + DB8500_DMA_MEMCPY_TX_1, + DB8500_DMA_MEMCPY_TX_2, + DB8500_DMA_MEMCPY_TX_3, + DB8500_DMA_MEMCPY_TX_4, + DB8500_DMA_MEMCPY_TX_5, +}; + +static struct stedma40_platform_data dma40_plat_data = { + .dev_len = ARRAY_SIZE(dma40_rx_map), + .dev_rx = dma40_rx_map, + .dev_tx = dma40_tx_map, + .memcpy = dma40_memcpy_event, + .memcpy_len = ARRAY_SIZE(dma40_memcpy_event), + .memcpy_conf_phy = &dma40_memcpy_conf_phy, + .memcpy_conf_log = &dma40_memcpy_conf_log, + /* Audio is using physical channel 2 from MMDSP */ + .disabled_channels = {2, -1}, +}; + +#ifdef CONFIG_UX500_CONTEXT +#define D40_DREG_GCC 0x000 +#define D40_DREG_LCPA 0x020 + +static void __iomem *base; + +static int dma_context_notifier_call(struct notifier_block *this, + unsigned long event, void *data) +{ + static unsigned long lcpa; + static unsigned long gcc; + + switch (event) { + case CONTEXT_APE_SAVE: + lcpa = readl(base + D40_DREG_LCPA); + gcc = readl(base + D40_DREG_GCC); + break; + + case CONTEXT_APE_RESTORE: + writel(gcc, base + D40_DREG_GCC); + writel(lcpa, base + D40_DREG_LCPA); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block dma_context_notifier = { + .notifier_call = dma_context_notifier_call, +}; + +static void dma_context_notifier_init(void) +{ + base = ioremap(dma40_resources[0].start, resource_size(&dma40_resources[0])); + if (WARN_ON(!base)) + return; + + WARN_ON(context_ape_notifier_register(&dma_context_notifier)); +} +#else +static void dma_context_notifier_init(void) +{ +} +#endif + +static struct platform_device dma40_device = { + .dev = { + .platform_data = &dma40_plat_data, + }, + .name = "dma40", + .id = 0, + .num_resources = ARRAY_SIZE(dma40_resources), + .resource = dma40_resources +}; + +void __init db8500_dma_init(void) +{ + int ret; + + if (cpu_is_u8500ed()) { + dma40_plat_data.memcpy = NULL; + dma40_plat_data.memcpy_len = 0; + dma40_resources[0].start = U8500_DMA_BASE_ED; + dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1; + dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED; + dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1; + } + + /* On DB8500v2+, RX line 30 is connected to MSP3 instead of MSP1 */ + if (!cpu_is_u8500ed() && !cpu_is_u8500v1()) + dma40_rx_map[DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE + + MSP_TX_RX_REG_OFFSET; + + ret = platform_device_register(&dma40_device); + if (ret) + dev_err(&dma40_device.dev, "unable to register device: %d\n", ret); + + dma_context_notifier_init(); +} diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c new file mode 100644 index 00000000000..25bd84eb3a6 --- /dev/null +++ b/arch/arm/mach-ux500/hotplug.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Based on ARM realview platform + * + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/completion.h> + +#include <asm/cacheflush.h> + +#include "pm/cpuidle.h" +#include "pm/context.h" + +extern volatile int pen_release; + +static DECLARE_COMPLETION(cpu_killed); + +static inline void platform_do_lowpower(unsigned int cpu) +{ + flush_cache_all(); + ux500_cpuidle_unplug(cpu); + for (;;) { + + context_varm_save_core(); + context_save_cpu_registers(); + + context_save_to_sram_and_wfi(false); + + context_restore_cpu_registers(); + context_varm_restore_core(); + + if (pen_release == cpu) { + /* + * OK, proper wakeup, we're done + */ + break; + } + } + ux500_cpuidle_plug(cpu); +} + +int platform_cpu_kill(unsigned int cpu) +{ + return wait_for_completion_timeout(&cpu_killed, 5000); +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ +#ifdef DEBUG + unsigned int this_cpu = hard_smp_processor_id(); + + if (cpu != this_cpu) { + printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", + this_cpu, cpu); + BUG(); + } +#endif + + printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); + complete(&cpu_killed); + + /* directly enter low power state, skipping secure registers */ + platform_do_lowpower(cpu); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-ux500/hwmem-int.c b/arch/arm/mach-ux500/hwmem-int.c new file mode 100644 index 00000000000..c23049df4a6 --- /dev/null +++ b/arch/arm/mach-ux500/hwmem-int.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Hardware memory driver integration + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/hwmem.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/slab.h> + +/* CONA API */ +void *cona_create(const char *name, phys_addr_t region_paddr, + size_t region_size); +void *cona_alloc(void *instance, size_t size); +void cona_free(void *instance, void *alloc); +phys_addr_t cona_get_alloc_paddr(void *alloc); +void *cona_get_alloc_kaddr(void *instance, void *alloc); +size_t cona_get_alloc_size(void *alloc); + +struct hwmem_mem_type_struct *hwmem_mem_types; +unsigned int hwmem_num_mem_types; + +static phys_addr_t hwmem_paddr; +static size_t hwmem_size; + +static int __init parse_hwmem_param(char *p) +{ + hwmem_size = memparse(p, &p); + + if (*p != '@') + goto no_at; + + hwmem_paddr = memparse(p + 1, &p); + + return 0; + +no_at: + hwmem_size = 0; + + return -EINVAL; +} +early_param("hwmem", parse_hwmem_param); + +static int __init setup_hwmem(void) +{ + static const unsigned int NUM_MEM_TYPES = 2; + + int ret; + + if (hwmem_paddr != PAGE_ALIGN(hwmem_paddr) || + hwmem_size != PAGE_ALIGN(hwmem_size) || hwmem_size == 0) { + printk(KERN_WARNING "HWMEM: hwmem_paddr !=" + " PAGE_ALIGN(hwmem_paddr) || hwmem_size !=" + " PAGE_ALIGN(hwmem_size) || hwmem_size == 0\n"); + return -ENOMSG; + } + + hwmem_mem_types = kzalloc(sizeof(struct hwmem_mem_type_struct) * + NUM_MEM_TYPES, GFP_KERNEL); + if (hwmem_mem_types == NULL) + return -ENOMEM; + + hwmem_mem_types[0].id = HWMEM_MEM_SCATTERED_SYS; + hwmem_mem_types[0].allocator_api.alloc = cona_alloc; + hwmem_mem_types[0].allocator_api.free = cona_free; + hwmem_mem_types[0].allocator_api.get_alloc_paddr = + cona_get_alloc_paddr; + hwmem_mem_types[0].allocator_api.get_alloc_kaddr = + cona_get_alloc_kaddr; + hwmem_mem_types[0].allocator_api.get_alloc_size = cona_get_alloc_size; + hwmem_mem_types[0].allocator_instance = cona_create("hwmem", + hwmem_paddr, hwmem_size); + if (IS_ERR(hwmem_mem_types[0].allocator_instance)) { + ret = PTR_ERR(hwmem_mem_types[0].allocator_instance); + goto hwmem_ima_init_failed; + } + + hwmem_mem_types[1] = hwmem_mem_types[0]; + hwmem_mem_types[1].id = HWMEM_MEM_CONTIGUOUS_SYS; + + hwmem_num_mem_types = NUM_MEM_TYPES; + + return 0; + +hwmem_ima_init_failed: + kfree(hwmem_mem_types); + + return ret; +} +arch_initcall_sync(setup_hwmem); + +enum hwmem_alloc_flags cachi_get_cache_settings( + enum hwmem_alloc_flags requested_cache_settings) +{ + static const u32 CACHE_ON_FLAGS_MASK = HWMEM_ALLOC_HINT_CACHED | + HWMEM_ALLOC_HINT_CACHE_WB | HWMEM_ALLOC_HINT_CACHE_WT | + HWMEM_ALLOC_HINT_CACHE_NAOW | HWMEM_ALLOC_HINT_CACHE_AOW | + HWMEM_ALLOC_HINT_INNER_AND_OUTER_CACHE | + HWMEM_ALLOC_HINT_INNER_CACHE_ONLY; + + enum hwmem_alloc_flags cache_settings; + + if (!(requested_cache_settings & CACHE_ON_FLAGS_MASK) && + requested_cache_settings & (HWMEM_ALLOC_HINT_NO_WRITE_COMBINE | + HWMEM_ALLOC_HINT_UNCACHED | HWMEM_ALLOC_HINT_WRITE_COMBINE)) + /* + * We never use uncached as it's extremely slow and there is + * no scenario where it would be better than buffered memory. + */ + return HWMEM_ALLOC_HINT_WRITE_COMBINE; + + /* + * The user has specified cached or nothing at all, both are treated as + * cached. + */ + cache_settings = (requested_cache_settings & + ~(HWMEM_ALLOC_HINT_UNCACHED | + HWMEM_ALLOC_HINT_NO_WRITE_COMBINE | + HWMEM_ALLOC_HINT_INNER_CACHE_ONLY | + HWMEM_ALLOC_HINT_CACHE_NAOW)) | + HWMEM_ALLOC_HINT_WRITE_COMBINE | HWMEM_ALLOC_HINT_CACHED | + HWMEM_ALLOC_HINT_CACHE_AOW | + HWMEM_ALLOC_HINT_INNER_AND_OUTER_CACHE; + if (!(cache_settings & (HWMEM_ALLOC_HINT_CACHE_WB | + HWMEM_ALLOC_HINT_CACHE_WT))) + cache_settings |= HWMEM_ALLOC_HINT_CACHE_WB; + /* + * On ARMv7 "alloc on write" is just a hint so we need to assume the + * worst case ie "alloc on write". We would however like to remember + * the requested "alloc on write" setting so that we can pass it on to + * the hardware, we use the reserved bit in the alloc flags to do that. + */ + if (requested_cache_settings & HWMEM_ALLOC_HINT_CACHE_AOW) + cache_settings |= HWMEM_ALLOC_RESERVED_CHI; + else + cache_settings &= ~HWMEM_ALLOC_RESERVED_CHI; + + return cache_settings; +} + +void cachi_set_pgprot_cache_options(enum hwmem_alloc_flags cache_settings, + pgprot_t *pgprot) +{ + if (cache_settings & HWMEM_ALLOC_HINT_CACHED) { + if (cache_settings & HWMEM_ALLOC_HINT_CACHE_WT) + *pgprot = __pgprot_modify(*pgprot, L_PTE_MT_MASK, + L_PTE_MT_WRITETHROUGH); + else { + if (cache_settings & HWMEM_ALLOC_RESERVED_CHI) + *pgprot = __pgprot_modify(*pgprot, + L_PTE_MT_MASK, L_PTE_MT_WRITEALLOC); + else + *pgprot = __pgprot_modify(*pgprot, + L_PTE_MT_MASK, L_PTE_MT_WRITEBACK); + } + } else { + *pgprot = pgprot_writecombine(*pgprot); + } +} diff --git a/arch/arm/mach-ux500/hwreg.c b/arch/arm/mach-ux500/hwreg.c new file mode 100644 index 00000000000..7ba3e0f2911 --- /dev/null +++ b/arch/arm/mach-ux500/hwreg.c @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2011 ST-Ericsson SA + * + * Author: Etienne CARRIERE <etienne.carriere@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + * + * HWREG: debug purpose module to map declared IOs and read/write + * access from debugfs entries. + * + * HWREG 32bit DB8500 v2.0 register access + * ======================================= + * + * 32bit read: + * # echo <addr> > <debugfs>/mem/reg-addr + * # cat <debugfs>/mem/reg-val + * + * 32bit write: + * # echo <addr> > <debugfs>/mem/reg-addr + * # echo <value> > <debugfs>/mem/reg-val + * + * <addr> 0x-prefixed hexadecimal + * <value> decimal or 0x-prefixed hexadecimal + * + * HWREG DB8500 formated read/write access + * ======================================= + * + * Read: read data, data>>SHIFT, data&=MASK, output data + * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE + * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data + * [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98] + * + * Usage: + * # echo "CMD [OPTIONS] ADRESS [VALUE]" > $debugfs/mem/hwreg + * + * CMD read read access + * write write access + * + * ADDRESS target reg physical addr (0x-hexa) + * + * VALUE (write) value to be updated + * + * OPTIONS + * -d|-dec (read) output in decimal + * -h|-hexa (read) output in 0x-hexa (default) + * -l|-w|-b 32bit (default), 16bit or 8bit reg access + * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF) + * -s|-shift SHIFT bit shift value (read:left, write:right) + * -o|-offset OFFSET address offset to add to ADDRESS value + * + * Warning: bit shift operation is applied to bit-mask. + * Warning: bit shift direction depends on read or right command. + * + * Examples: + * + * before: [*ADDRESS = 0xABCDEF98] + * # echo read -h -mask 0xFFF -shift 12 ADDRESS > hwreg + * # cat hwreg-shift + * 0x0000CDE + * # echo write -h -mask 0xFFF -shift 12 ADDRESS 0x123 > hwreg + * # cat hwreg-shift + * 0x0000123 + * after [*ADDRESS = 0xAB123F98] + * + * before: [*ADDRESS = 0xABCDEF98] + * # echo read -h -mask 0x00F0F000 ADDRESS 0x12345678 > hwreg + * # cat hwreg-shift + * 0x00C0E000 + * # echo write -h -mask 0x00F0F000 ADDRESS 0x12345678 > hwreg + * # cat hwreg-shift + * 0xAB3D5F98 + * after [*ADDRESS = 0xAB123F98] + * + * Read DB8500 version (full ID, chip version ID, chip version ID): + * + * echo read 0x9001DBF4 > hwreg + * cat hwreg + * echo read -m 0xFFFF -s 8 0x9001DBF4 > hwreg + * cat hwreg + * echo read -m 0xFF -s 0 0x9001DBF4 > hwreg + * cat hwreg + * + * Read and Enable/Disable I2C PRCMU clock: + * + * printf "I2CCLK = " && echo read -m 1 -s 8 0x80157520 > hwreg + * cat /sys/kernel/debug/db8500/hwreg + * printf "I2CCLK off" && echo write -m 1 -s 8 0x80157518 1 > hwreg + * printf "I2CCLK on" && echo write -m 1 -s 8 0x80157510 1 > hwreg + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/string.h> +#include <linux/ctype.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +#include <mach/hardware.h> + +/* + * temporary definitions + * The following declarations are to be removed + * when kernel/arch/arm/mach-ux8500/include/mach/db8500-regs.h is up-to-date + */ + +/* DDR-SDRAM chip-select 0 (0x0000 0000 : 0x1FFF FFFF) */ +#ifndef U8500_SCU_CD_R4_BASE +#define U8500_SCU_CD_R4_BASE 0x17c40000 +#endif + +#ifndef U8500_SCU_AD_R4_BASE +#define U8500_SCU_AD_R4_BASE 0x17d40000 +#endif + +#ifndef U8500_HSI2CMODEMR4_BASE +#define U8500_HSI2CMODEMR4_BASE 0x17e02000 +#endif +/* End of temporary definitions */ + +static struct dentry *hwreg_debugfs_dir; + +/* 32bit read/write ressources */ +static u32 debug_address; /* shared: single read/write access */ + +/* hwreg entry ressources */ +struct hwreg_cfg { + uint addr; /* target physical addr to access */ + uint fmt; /* format */ + uint mask; /* read/write mask, applied before any bit shift */ + int shift; /* bit shift (read:right shift, write:left shift */ +}; +#define REG_FMT_DEC(c) ((c)->fmt & 0x1) /* bit 0: 0=hexa, 1=dec */ +#define REG_FMT_HEX(c) (!REG_FMT_DEC(c)) /* bit 0: 0=hexa, 1=dec */ +#define REG_FMT_32B(c) (((c)->fmt & 0x6)==0x0) /* bit[2:1]=0 => 32b access */ +#define REG_FMT_16B(c) (((c)->fmt & 0x6)==0x2) /* bit[2:1]=1 => 16b access */ +#define REG_FMT_8B(c) (((c)->fmt & 0x6)==0x4) /* bit[2:1]=2 => 8b access */ + +static struct hwreg_cfg hwreg_cfg = { + .addr = 0, /* default: invalid phys addr */ + .fmt = 0, /* default: 32bit access, hex output */ + .mask = 0xFFFFFFFF, /* default: no mask */ + .shift = 0, /* default: no bit shift */ +}; + +/* HWREG guts: mapping table */ + +struct hwreg_io_range { + u32 base; + u32 size; + u8 *addr; +}; + +/* + * HWREG guts: mapping table + */ +static struct hwreg_io_range hwreg_io_map[] = { + /* Periph1 Peripherals */ + {.base = U8500_PER1_BASE, .size = 0x10000}, + /* Periph2 Peripherals */ + {.base = U8500_PER2_BASE, .size = 0x10000}, + /* Periph3 Peripherals */ + {.base = U8500_PER3_BASE, .size = 0x10000}, + /* Periph4 Peripherals */ + {.base = U8500_PER4_BASE, .size = 0x70000}, + /* Periph5 Periphals */ + {.base = U8500_PER5_BASE, .size = 0x20000}, + /* Periph6 Peripherals */ + {.base = U8500_PER6_BASE, .size = 0x10000}, + /* + * Snoop Control Unit, A9 Private interrupt IF, + * A9 private peripherals, Level-2 Cache Configuration registers, + * and some reserved area + */ + {.base = U8500_SCU_BASE, .size = 0x4000}, + + /* DISPLAY Ctrl. configuration registers */ + {.base = U8500_MCDE_BASE, .size = SZ_4K}, + + /* DSI1 link registers */ + {.base = U8500_DSI_LINK1_BASE, .size = SZ_4K}, + + /* DSI2 link registers */ + {.base = U8500_DSI_LINK2_BASE, .size = SZ_4K}, + + /* DSI3 link registers */ + {.base = U8500_DSI_LINK3_BASE, .size = SZ_4K}, + + /* DMA Ctrl. configuration registers (base address changed in V1) */ + {.base = U8500_DMA_BASE, .size = SZ_4K}, + + /* 0xB7A00000 -> 0xB7E04000: Modem I2C */ + {.base = U8500_MODEM_I2C, .size = 0x404000}, + + /* 0xA0390000 -> 0xA039FFFF: SBAG configuration registers */ + {.base = U8500_SBAG_BASE, .size = SZ_4K}, + + /* 0xA0300000 -> 0xA031FFFF: SGA configuration registers */ + {.base = U8500_SGA_BASE, .size = 0x10000}, + + /* 0xA0200000 -> 0xA02FFFFF: Smart Imaging Acc. Data Memory space (SIA) */ + {.base = U8500_SIA_BASE, .size = 0x60000}, + + /* 0xA0100000 -> 0xA01FFFFF: Smart Video Acc. Data Memory space (SVA) */ + {.base = U8500_SVA_BASE, .size = 0x60000}, + + /* 0x81000000 -> 0x8103FFFF: Main ICN Crossbar configuration registers */ + {.base = U8500_ICN_BASE, .size = 0x2000}, + + /* 0x80140000 -> 0x8014FFFF: HSEM (Semaphores) configuration */ + {.base = U8500_HSEM_BASE, .size = SZ_4K}, + + /* 0x80130000 -> 0x8013FFFF: B2R2 configuration registers */ + {.base = U8500_B2R2_BASE, .size = SZ_4K}, + + /* 0x80100000 -> 0x8010FFFF: STM */ + {.base = U8500_STM_BASE, .size = 0x10000}, + + /* High part of embedded boot ROM */ + {.base = U8500_ASIC_ID_BASE, .size = SZ_4K}, + + /* 0x17C4 0000 : 0x17C4 007C */ + {.base = U8500_SCU_CD_R4_BASE, .size = SZ_4K}, + + /* 0x17D4 0000 : 0x17D4 041C */ + {.base = U8500_SCU_AD_R4_BASE, .size = SZ_4K}, + + /* 0x17E0 2000 : 0x17E0 2FFC */ + {.base = U8500_HSI2CMODEMR4_BASE, .size = SZ_4K}, + + {.base = 0, .size = 0, }, + +}; + +static void hwreg_io_init(void) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) { + hwreg_io_map[i].addr = ioremap(hwreg_io_map[i].base, + hwreg_io_map[i].size); + if (!hwreg_io_map[i].addr) + printk(KERN_WARNING + "%s: ioremap for %d (%08x) failed\n", + __func__, i, hwreg_io_map[i].base); + } +} + +static void hwreg_io_exit(void) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) + if (hwreg_io_map[i].addr) + iounmap(hwreg_io_map[i].addr); +} + +static void *hwreg_io_ptov(u32 phys) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) { + u32 base = hwreg_io_map[i].base; + u32 size = hwreg_io_map[i].size; + u8 *addr = hwreg_io_map[i].addr; + + if (phys < base || phys >= base + size) + continue; + + if (addr) + return addr + phys - base; + + break; + } + + return NULL; +} + + +/* + * HWREG 32bit DB8500 register read/write access debugfs part + */ + +static int hwreg_address_print(struct seq_file *s, void *p) +{ + return seq_printf(s, "0x%08X\n", debug_address); +} + +static int hwreg_address_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_address_print, inode->i_private); +} + +static ssize_t hwreg_address_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + unsigned long user_address; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if(strict_strtoul(buf, 0, &user_address)) + return -EINVAL; + if (hwreg_io_ptov(user_address)==NULL) + return -EADDRNOTAVAIL; + + debug_address = user_address; + return buf_size; +} + +static int hwreg_value_print(struct seq_file *s, void *p) +{ + void *ptr; + + ptr = hwreg_io_ptov(debug_address); + if (ptr == NULL) + return -EADDRNOTAVAIL; + seq_printf(s, "0x%X\n", readl(ptr)); + return 0; +} + +static int hwreg_value_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_value_print, inode->i_private); +} + +static ssize_t hwreg_value_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + unsigned long user_val; + void *ptr; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (strict_strtoul(buf, 0, &user_val)) + return -EINVAL; + + if ((ptr = hwreg_io_ptov(debug_address)) == NULL) + return -EFAULT; + writel(user_val, ptr); + return buf_size; +} + +static const struct file_operations hwreg_address_fops = { + .open = hwreg_address_open, + .write = hwreg_address_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; +static const struct file_operations hwreg_value_fops = { + .open = hwreg_value_open, + .write = hwreg_value_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* 'map' read entry: display current HWREG IO mapping table */ +static int hwreg_map_print(struct seq_file *s, void *p) +{ + int err, i; + for (i = 0; hwreg_io_map[i].base; ++i) { + err = seq_printf(s, "%d: 0x%08X => 0x%08X\n", + i, hwreg_io_map[i].base, + hwreg_io_map[i].base+hwreg_io_map[i].size); + if (err < 0) + return -ENOMEM; + } + return 0; +} +static int hwreg_map_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_map_print, inode->i_private); +} + +static const struct file_operations hwreg_map_fops = { + .open = hwreg_map_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* + * HWREG DB8500 formated routines + */ + +static int hwreg_print(struct seq_file *s, void *d) +{ + struct hwreg_cfg *c = (struct hwreg_cfg*) s->private; + void *p; + uint v; + + if ((c==NULL) || ((p = hwreg_io_ptov(c->addr))==NULL)) + return -EADDRNOTAVAIL; + + v = (uint) (REG_FMT_32B(c) ? readl(p) : REG_FMT_16B(c) ? readw(p) : readb(p)); + v = (c->shift>=0) ? v >> c->shift : v << (-c->shift); + v = v & c->mask; + + if (REG_FMT_DEC(c)) + seq_printf(s, "%d\n", v); + else if (REG_FMT_32B(c)) + seq_printf(s, "0x%08X\n", v); + else if (REG_FMT_32B(c)) + seq_printf(s, "0x%04X\n", v); + else + seq_printf(s, "0x%02X\n", v); + return 0; +} + +static int hwreg_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_print, inode->i_private); +} + +/* + * return length of an ASCII numerical value, 0 is string is not a numerical + * value. string shall start at value 1st char. + * string can be tailed with \0 or space or newline chars only. + * value can be decimal or hexadecimal (prefixed 0x or 0X). + */ +static int strval_len(char *b) +{ + char *s = b; + if((*s=='0') && ((*(s+1)=='x') || (*(s+1)=='X'))) { + s += 2; + for (; *s && (*s!=' ') && (*s!='\n'); s++) { + if (!isxdigit(*s)) + return 0; + } + } else { + if (*s=='-') + s++; + for (; *s && (*s!=' ') && (*s!='\n'); s++) { + if (!isdigit(*s)) + return 0; + } + } + return (int) (s-b); +} + +/* + * parse hwreg input data. + * update global hwreg_cfg only if input data syntax is ok. + */ +static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) +{ + uint write, val=0, offset=0; + struct hwreg_cfg loc = { + .addr = 0, /* default: invalid phys addr */ + .fmt = 0, /* default: 32bit access, hex output */ + .mask = 0xFFFFFFFF, /* default: no mask */ + .shift = 0, /* default: no bit shift */ + }; + + /* read or write ? */ + if(!strncmp(b, "read ", 5)) { + write = 0; + b += 5; + } else if (!strncmp(b, "write ", 6)) { + write = 1; + b += 6; + } else { + return -EINVAL; + } + + /* OPTIONS -l|-w|-b -s -m -o */ + while((*b==' ') || (*b=='-')) { + if (*(b-1)!=' ') { + b++; + continue; + } + if ((!strncmp(b, "-d ", 3)) || (!strncmp(b, "-dec ", 5))) { + b += (*(b+2)==' ') ? 3 : 5; + loc.fmt |= (1<<0); + } else if ((!strncmp(b, "-h ", 3)) || (!strncmp(b, "-hex ", 5))) { + b += (*(b+2)==' ') ? 3 : 5; + loc.fmt &= ~(1<<0); + } else if ((!strncmp(b, "-m ", 3)) || (!strncmp(b, "-mask ", 6))) { + b += (*(b+2)==' ') ? 3 : 6; + if (strval_len(b)==0) + return -EINVAL; + loc.mask = simple_strtoul(b, &b, 0); + } else if ((!strncmp(b, "-s ", 3)) || (!strncmp(b,"-shift ", 7))) { + b += (*(b+2)==' ') ? 3 : 7; + if (strval_len(b)==0) + return -EINVAL; + loc.shift = simple_strtol(b, &b, 0); + + } else if ((!strncmp(b, "-o ", 3)) || (!strncmp(b,"-offset ", 8))) { + b += (*(b+2)==' ') ? 3 : 8; + if (strval_len(b)==0) + return -EINVAL; + offset = simple_strtol(b, &b, 0); + } else if (!strncmp(b, "-l ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (0<<1); + } else if (!strncmp(b, "-w ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (1<<1); + } else if (!strncmp(b, "-b ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (2<<1); + } else { + return -EINVAL; + } + } + /* get arg ADDRESS */ + if (strval_len(b)==0) + return -EINVAL; + loc.addr = simple_strtoul(b, &b, 0); + loc.addr += offset; + if (hwreg_io_ptov(loc.addr) == NULL) + return -EINVAL; + + if (write) { + while(*b==' ') b++; /* skip spaces up to arg VALUE */ + if (strval_len(b)==0) + return -EINVAL; + val = simple_strtoul(b, &b, 0); + } + + /* args are ok, update target cfg (mainly for read) */ + *cfg = loc; + +#ifdef DEBUG + printk(KERN_INFO "HWREG request: %s %d-bit reg, %s, addr=0x%08X, " + "mask=0x%X, shift=%d value=0x%X\n", + (write)?"write":"read", + REG_FMT_32B(cfg)?32:REG_FMT_16B(cfg)?16:8, + REG_FMT_DEC(cfg)?"decimal":"hexa", + cfg->addr, cfg->mask, cfg->shift, val); +#endif + + if (write) { + void *p = hwreg_io_ptov(cfg->addr); + uint d = (uint) (REG_FMT_32B(cfg)) ? readl(p) : + (REG_FMT_16B(cfg)) ? readw(p) : readb(p); + + if (cfg->shift>=0) { + d &= ~(cfg->mask << (cfg->shift)); + val = (val & cfg->mask) << (cfg->shift); + } else { + d &= ~(cfg->mask >> (-cfg->shift)); + val = (val & cfg->mask) >> (-cfg->shift); + } + val = val | d; + + /* read reg, reset mask field and update value bit-field */ + if (REG_FMT_32B(cfg)) + writel(val, p); + else if (REG_FMT_16B(cfg)) + writew(val, p); + else + writeb(val, p); + } + return 0; +} + +static ssize_t hwreg_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[128]; + int buf_size, ret; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* get args and process */ + ret = hwreg_common_write(buf, &hwreg_cfg); + return (ret) ? ret : buf_size; +} + +static const struct file_operations hwreg_fops = { + .open = hwreg_open, + .write = hwreg_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* + * hwreg module init/cleanup + */ +static int __init hwreg_initialize(void) +{ + static struct dentry *file; + hwreg_io_init(); + + hwreg_debugfs_dir = debugfs_create_dir("mem", NULL); + if (!hwreg_debugfs_dir) + goto debugfs_err; + + file = debugfs_create_file("reg-addr", + (S_IRUGO | S_IWUGO), hwreg_debugfs_dir, + NULL, &hwreg_address_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("reg-val", + (S_IRUGO | S_IWUGO), hwreg_debugfs_dir, + NULL, &hwreg_value_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("reg-map", + (S_IRUGO), + hwreg_debugfs_dir, NULL, &hwreg_map_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("hwreg", + (S_IRUGO), + hwreg_debugfs_dir, &hwreg_cfg, &hwreg_fops); + if (!file) + goto debugfs_err; + return 0; + +debugfs_err: + if (hwreg_debugfs_dir) + debugfs_remove_recursive(hwreg_debugfs_dir); + printk(KERN_ERR "hwreg: failed to register debugfs entries.\n"); + return -1; +} + +static void __exit hwreg_finalize(void) +{ + debugfs_remove_recursive(hwreg_debugfs_dir); + hwreg_io_exit(); +} + +module_init(hwreg_initialize); +module_exit(hwreg_finalize); + +MODULE_AUTHOR("ST-Ericsson"); +MODULE_DESCRIPTION("DB8500 HW registers access through debugfs"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ux500/include/mach/ab8500-accdet.h b/arch/arm/mach-ux500/include/mach/ab8500-accdet.h new file mode 100644 index 00000000000..b1b157e317e --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500-accdet.h @@ -0,0 +1,96 @@ +/* + * Copyright ST-Ericsson 2011. + * + * Author: Jarmo K. Kuronen <jarmo.kuronen@symbio.com> for ST Ericsson. + * Licensed under GPLv2. + */ + +#ifndef _AB8500_ACCDET_H +#define _AB8500_ACCDET_H + +/* +* Debounce times for AccDet1 input +* @0x880 [2:0] +*/ +#define ACCDET1_DB_0ms 0x00 +#define ACCDET1_DB_10ms 0x01 +#define ACCDET1_DB_20ms 0x02 +#define ACCDET1_DB_30ms 0x03 +#define ACCDET1_DB_40ms 0x04 +#define ACCDET1_DB_50ms 0x05 +#define ACCDET1_DB_60ms 0x06 +#define ACCDET1_DB_70ms 0x07 + +/* +* Voltage threshold for AccDet1 input +* @0x880 [6:3] +*/ +#define ACCDET1_TH_1100mV 0x40 +#define ACCDET1_TH_1200mV 0x48 +#define ACCDET1_TH_1300mV 0x50 +#define ACCDET1_TH_1400mV 0x58 +#define ACCDET1_TH_1500mV 0x60 +#define ACCDET1_TH_1600mV 0x68 +#define ACCDET1_TH_1700mV 0x70 +#define ACCDET1_TH_1800mV 0x78 + +/* +* Voltage threshold for AccDet21 input +* @0x881 [3:0] +*/ +#define ACCDET21_TH_300mV 0x00 +#define ACCDET21_TH_400mV 0x01 +#define ACCDET21_TH_500mV 0x02 +#define ACCDET21_TH_600mV 0x03 +#define ACCDET21_TH_700mV 0x04 +#define ACCDET21_TH_800mV 0x05 +#define ACCDET21_TH_900mV 0x06 +#define ACCDET21_TH_1000mV 0x07 +#define ACCDET21_TH_1100mV 0x08 +#define ACCDET21_TH_1200mV 0x09 +#define ACCDET21_TH_1300mV 0x0a +#define ACCDET21_TH_1400mV 0x0b +#define ACCDET21_TH_1500mV 0x0c +#define ACCDET21_TH_1600mV 0x0d +#define ACCDET21_TH_1700mV 0x0e +#define ACCDET21_TH_1800mV 0x0f + +/* +* Voltage threshold for AccDet22 input +* @0x881 [7:4] +*/ +#define ACCDET22_TH_300mV 0x00 +#define ACCDET22_TH_400mV 0x10 +#define ACCDET22_TH_500mV 0x20 +#define ACCDET22_TH_600mV 0x30 +#define ACCDET22_TH_700mV 0x40 +#define ACCDET22_TH_800mV 0x50 +#define ACCDET22_TH_900mV 0x60 +#define ACCDET22_TH_1000mV 0x70 +#define ACCDET22_TH_1100mV 0x80 +#define ACCDET22_TH_1200mV 0x90 +#define ACCDET22_TH_1300mV 0xa0 +#define ACCDET22_TH_1400mV 0xb0 +#define ACCDET22_TH_1500mV 0xc0 +#define ACCDET22_TH_1600mV 0xd0 +#define ACCDET22_TH_1700mV 0xe0 +#define ACCDET22_TH_1800mV 0xf0 + +/** + * struct ab8500_accdet_platform_data - AV Accessory detection specific + * platform data + * @btn_keycode Keycode to be sent when accessory button is pressed. + * @accdet1_dbth Debounce time + voltage threshold for accdet 1 input. + * @accdet2122_th Voltage thresholds for accdet21 and accdet22 inputs. + * @is_detection_inverted Whether the accessory insert/removal, button + * press/release irq's are inverted. + */ +struct ab8500_accdet_platform_data { + int btn_keycode; + u8 accdet1_dbth; + u8 accdet2122_th; + unsigned int video_ctrl_gpio; + bool is_detection_inverted; +}; + +#endif /* _AB8500_ACCDET_H */ diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec.h b/arch/arm/mach-ux500/include/mach/ab8500_codec.h new file mode 100644 index 00000000000..d45dea66b5d --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500_codec.h @@ -0,0 +1,327 @@ +/*****************************************************************************/ +/** +* © ST-Ericsson, 2009 - All rights reserved +* Reproduction and Communication of this document is strictly prohibited +* unless specifically authorized in writing by ST-Ericsson +* +* \brief Public header file for AB8500 Codec +* \author ST-Ericsson +*/ +/*****************************************************************************/ + +#ifndef _AB8500_CODEC_H_ +#define _AB8500_CODEC_H_ + +/*--------------------------------------------------------------------- + * Includes + *--------------------------------------------------------------------*/ +#include "hcl_defs.h" +#include "debug.h" +#include <mach/ab8500_codec_p.h> + +/*--------------------------------------------------------------------- + * Define + *--------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { + AB8500_CODEC_OK, + AB8500_CODEC_ERROR, + AB8500_CODEC_UNSUPPORTED_FEATURE, + AB8500_CODEC_INVALID_PARAMETER, + AB8500_CODEC_CONFIG_NOT_COHERENT, + AB8500_CODEC_TRANSACTION_FAILED + } t_ab8500_codec_error; + + typedef enum { + AB8500_CODEC_MASTER_MODE_DISABLE, + AB8500_CODEC_MASTER_MODE_ENABLE + } t_ab8500_codec_master_mode; + + typedef enum { + AB8500_CODEC_SLOT0, + AB8500_CODEC_SLOT1, + AB8500_CODEC_SLOT2, + AB8500_CODEC_SLOT3, + AB8500_CODEC_SLOT4, + AB8500_CODEC_SLOT5, + AB8500_CODEC_SLOT6, + AB8500_CODEC_SLOT7, + AB8500_CODEC_SLOT8, + AB8500_CODEC_SLOT9, + AB8500_CODEC_SLOT10, + AB8500_CODEC_SLOT11, + AB8500_CODEC_SLOT12, + AB8500_CODEC_SLOT13, + AB8500_CODEC_SLOT14, + AB8500_CODEC_SLOT15, + AB8500_CODEC_SLOT16, + AB8500_CODEC_SLOT17, + AB8500_CODEC_SLOT18, + AB8500_CODEC_SLOT19, + AB8500_CODEC_SLOT20, + AB8500_CODEC_SLOT21, + AB8500_CODEC_SLOT22, + AB8500_CODEC_SLOT23, + AB8500_CODEC_SLOT24, + AB8500_CODEC_SLOT25, + AB8500_CODEC_SLOT26, + AB8500_CODEC_SLOT27, + AB8500_CODEC_SLOT28, + AB8500_CODEC_SLOT29, + AB8500_CODEC_SLOT30, + AB8500_CODEC_SLOT31, + AB8500_CODEC_SLOT_UNDEFINED + } t_ab8500_codec_slot; + + typedef enum { + AB8500_CODEC_DA_CHANNEL_NUMBER_1, + AB8500_CODEC_DA_CHANNEL_NUMBER_2, + AB8500_CODEC_DA_CHANNEL_NUMBER_3, + AB8500_CODEC_DA_CHANNEL_NUMBER_4, + AB8500_CODEC_DA_CHANNEL_NUMBER_5, + AB8500_CODEC_DA_CHANNEL_NUMBER_6, + AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED + } t_ab8500_codec_da_channel_number; + + typedef enum { + AB8500_CODEC_SRC_STATE_DISABLE, + AB8500_CODEC_SRC_STATE_ENABLE + } t_ab8500_codec_src_state; + + typedef enum { + AB8500_CODEC_DEST_STATE_DISABLE, + AB8500_CODEC_DEST_STATE_ENABLE + } t_ab8500_codec_dest_state; + + typedef struct { + t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr; + t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr; + t_ab8500_codec_cr28_if0wl cr28_if0wl; + t_ab8500_codec_cr30_if1wl cr30_if1wl; + t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p; + t_ab8500_codec_cr28_if0del cr28_if0del; + } t_ab8500_codec_tdm_config; + + typedef struct { + t_ab8500_codec_cr104_bfifoint cr104_bfifoint; + t_ab8500_codec_cr105_bfifotx cr105_bfifotx; + t_ab8500_codec_cr106_bfifofsext cr106_bfifofsext; + t_ab8500_codec_cr106_bfifomsk cr106_bfifomsk; + t_ab8500_codec_cr106_bfifomstr cr106_bfifomstr; + t_ab8500_codec_cr106_bfifostrt cr106_bfifostrt; + t_ab8500_codec_cr107_bfifosampnr cr107_bfifosampnr; + t_ab8500_codec_cr108_bfifowakeup cr108_bfifowakeup; + } t_ab8500_codec_burst_fifo_config; + +/************************************************************/ +/*--------------------------------------------------------------------- + * Exported APIs + *--------------------------------------------------------------------*/ +/* Initialization */ + t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8 + slave_address_of_codec); + t_ab8500_codec_error AB8500_CODEC_Reset(void); + +/* Audio Codec basic configuration */ + t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction, + IN + t_ab8500_codec_mode + ab8500_codec_mode_in, + IN + t_ab8500_codec_mode + ab8500_codec_mode_out, + IN + t_ab8500_codec_tdm_config + const *const + p_tdm_config); + t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src + ab8500_codec_src); + t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest + ab8500_codec_dest); + +/* Burst FIFO configuration */ + t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN + t_ab8500_codec_burst_fifo_config + const *const + p_burst_fifo_config); + t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void); + t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void); + +/* Audio Codec Master mode configuration */ + t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN + t_ab8500_codec_master_mode + mode); + +/* APIs to be implemented by user */ + t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset, + IN t_uint8 count, + IN t_uint8 * p_data); + t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset, + IN t_uint8 count, + IN t_uint8 * p_dummy_data, + IN t_uint8 * p_data); + +/* Volume Management */ + t_ab8500_codec_error AB8500_CODEC_SetSrcVolume(IN t_ab8500_codec_src + src_device, + IN t_uint8 + in_left_volume, + IN t_uint8 + in_right_volume); + t_ab8500_codec_error AB8500_CODEC_SetDestVolume(IN t_ab8500_codec_dest + dest_device, + IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume); + +/* Power management */ + t_ab8500_codec_error AB8500_CODEC_PowerDown(void); + t_ab8500_codec_error AB8500_CODEC_PowerUp(void); + +/* Interface Management */ + t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN + t_ab8500_codec_audio_interface + audio_interface); + t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT + t_ab8500_codec_audio_interface + * p_audio_interface); + +/* Slot Allocation */ + t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); + t_ab8500_codec_error AB8500_CODEC_DASlotAllocation(IN + t_ab8500_codec_da_channel_number + channel_number, + IN + t_ab8500_codec_cr51_to_cr56_sltoda + slot); + +/* Loopback Management */ + t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume); + t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void); + +/* Bypass Management */ + t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void); + t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void); + +/* Power Control Management */ + t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); + t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN + t_ab8500_codec_dest + dest_device, + t_ab8500_codec_dest_state + state); + +/* Version Management */ + t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version); + +#if 0 +/* Debug management */ + t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level); + t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level * + p_dbg_level); +#endif + +/* +** following is added by $kardad$ +*/ + +/* duplicate copy of enum from msp.h */ +/* for MSPConfiguration.in_clock_freq parameter to select msp clock freq */ + typedef enum { + CODEC_MSP_INPUT_FREQ_1MHZ = 1024, + CODEC_MSP_INPUT_FREQ_2MHZ = 2048, + CODEC_MSP_INPUT_FREQ_3MHZ = 3072, + CODEC_MSP_INPUT_FREQ_4MHZ = 4096, + CODEC_MSP_INPUT_FREQ_5MHZ = 5760, + CODEC_MSP_INPUT_FREQ_6MHZ = 6144, + CODEC_MSP_INPUT_FREQ_8MHZ = 8192, + CODEC_MSP_INPUT_FREQ_11MHZ = 11264, + CODEC_MSP_INPUT_FREQ_12MHZ = 12288, + CODEC_MSP_INPUT_FREQ_16MHZ = 16384, + CODEC_MSP_INPUT_FREQ_22MHZ = 22579, + CODEC_MSP_INPUT_FREQ_24MHZ = 24576, + CODEC_MSP_INPUT_FREQ_48MHZ = 49152 + } codec_msp_in_clock_freq_type; + +/* msp clock source internal/external for srg_clock_sel */ + typedef enum { + CODEC_MSP_APB_CLOCK = 0, + CODEC_MSP_SCK_CLOCK = 2, + CODEC_MSP_SCK_SYNC_CLOCK = 3 + } codec_msp_srg_clock_sel_type; + +/* Sample rate supported by Codec */ + + typedef enum { + CODEC_FREQUENCY_DONT_CHANGE = -100, + CODEC_SAMPLING_FREQ_RESET = -1, + CODEC_SAMPLING_FREQ_MINLIMIT = 7, + CODEC_SAMPLING_FREQ_8KHZ = 8, /*default */ + CODEC_SAMPLING_FREQ_11KHZ = 11, + CODEC_SAMPLING_FREQ_12KHZ = 12, + CODEC_SAMPLING_FREQ_16KHZ = 16, + CODEC_SAMPLING_FREQ_22KHZ = 22, + CODEC_SAMPLING_FREQ_24KHZ = 24, + CODEC_SAMPLING_FREQ_32KHZ = 32, + CODEC_SAMPLING_FREQ_44KHZ = 44, + CODEC_SAMPLING_FREQ_48KHZ = 48, + CODEC_SAMPLING_FREQ_64KHZ = 64, /*the frequencies below this line are not supported in stw5094A */ + CODEC_SAMPLING_FREQ_88KHZ = 88, + CODEC_SAMPLING_FREQ_96KHZ = 96, + CODEC_SAMPLING_FREQ_128KHZ = 128, + CODEC_SAMPLING_FREQ_176KHZ = 176, + CODEC_SAMPLING_FREQ_192KHZ = 192, + CODEC_SAMPLING_FREQ_MAXLIMIT = 193 + } t_codec_sample_frequency; + +#define RESET -1 +#define DEFAULT -100 +/***********************************************************/ +/* +** following stuff is added to compile code without debug print support $kardad$ +*/ + +#define DBGEXIT(cr) +#define DBGEXIT0(cr) +#define DBGEXIT1(cr,ch,p1) +#define DBGEXIT2(cr,ch,p1,p2) +#define DBGEXIT3(cr,ch,p1,p2,p3) +#define DBGEXIT4(cr,ch,p1,p2,p3,p4) +#define DBGEXIT5(cr,ch,p1,p2,p3,p4,p5) +#define DBGEXIT6(cr,ch,p1,p2,p3,p4,p5,p6) + +#define DBGENTER() +#define DBGENTER0() +#define DBGENTER1(ch,p1) +#define DBGENTER2(ch,p1,p2) +#define DBGENTER3(ch,p1,p2,p3) +#define DBGENTER4(ch,p1,p2,p3,p4) +#define DBGENTER5(ch,p1,p2,p3,p4,p5) +#define DBGENTER6(ch,p1,p2,p3,p4,p5,p6) + +#define DBGPRINT(dbg_level,dbg_string) +#define DBGPRINTHEX(dbg_level,dbg_string,uint32) +#define DBGPRINTDEC(dbg_level,dbg_string,uint32) +/***********************************************************/ + +#ifdef __cplusplus +} /* allow C++ to use these headers */ +#endif /* __cplusplus */ +#endif /* _AB8500_CODEC_H_ */ +/* End of file ab8500_codec.h*/ diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h new file mode 100644 index 00000000000..847a1729e44 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h @@ -0,0 +1,3082 @@ +/*****************************************************************************/ +/** +* © ST-Ericsson, 2009 - All rights reserved +* Reproduction and Communication of this document is strictly prohibited +* unless specifically authorized in writing by ST-Ericsson + * +* \brief Private Header file for AB8500 CODEC +* \author ST-Ericsson + */ +/*****************************************************************************/ + +#ifndef _AB8500_CODECP_H_ +#define _AB8500_CODECP_H_ + +/*---------------------------------------------------------------------------- + * Includes + *---------------------------------------------------------------------------*/ +#include "hcl_defs.h" + +#define AB8500_CODEC_HCL_VERSION_ID 2 +#define AB8500_CODEC_HCL_MAJOR_ID 0 +#define AB8500_CODEC_HCL_MINOR_ID 0 + +#define AB8500_CODEC_MASK_ONE_BIT 0x1UL +#define AB8500_CODEC_MASK_TWO_BITS 0x3UL +#define AB8500_CODEC_MASK_THREE_BITS 0x7UL +#define AB8500_CODEC_MASK_FOUR_BITS 0xFUL +#define AB8500_CODEC_MASK_FIVE_BITS 0x1FUL +#define AB8500_CODEC_MASK_SIX_BITS 0x3FUL +#define AB8500_CODEC_MASK_SEVEN_BITS 0x7FUL +#define AB8500_CODEC_MASK_EIGHT_BITS 0xFFUL + +#define AB8500_CODEC_WRITE_BITS(reg, val, bit_nb, pos) (reg) = ((t_uint8) ((((reg) & (~(bit_nb << pos))) | (((val) & bit_nb) << pos)))) + +#define AB8500_CODEC_BLOCK 0x0D + +#define AB8500_CODEC_MASK_TWO_MS_BITS 0xC0UL +#define AB8500_CODEC_MASK_SIX_LS_BITS 0x3FUL + +/* Genepi AudioCodec Control Registers */ + +#define AB8500_CODEC_CR0 0x00 +#define AB8500_CODEC_CR1 0x01 +#define AB8500_CODEC_CR2 0x02 +#define AB8500_CODEC_CR3 0x03 +#define AB8500_CODEC_CR4 0x04 +#define AB8500_CODEC_CR5 0x05 +#define AB8500_CODEC_CR6 0x06 +#define AB8500_CODEC_CR7 0x07 +#define AB8500_CODEC_CR8 0x08 +#define AB8500_CODEC_CR9 0x09 +#define AB8500_CODEC_CR10 0x0A +#define AB8500_CODEC_CR11 0x0B +#define AB8500_CODEC_CR12 0x0C +#define AB8500_CODEC_CR13 0x0D +#define AB8500_CODEC_CR14 0x0E +#define AB8500_CODEC_CR15 0x0F +#define AB8500_CODEC_CR16 0x10 +#define AB8500_CODEC_CR17 0x11 +#define AB8500_CODEC_CR18 0x12 +#define AB8500_CODEC_CR19 0x13 +#define AB8500_CODEC_CR20 0x14 +#define AB8500_CODEC_CR21 0x15 +#define AB8500_CODEC_CR22 0x16 +#define AB8500_CODEC_CR23 0x17 +#define AB8500_CODEC_CR24 0x18 +#define AB8500_CODEC_CR25 0x19 +#define AB8500_CODEC_CR26 0x1A +#define AB8500_CODEC_CR27 0x1B +#define AB8500_CODEC_CR28 0x1C +#define AB8500_CODEC_CR29 0x1D +#define AB8500_CODEC_CR30 0x1E +#define AB8500_CODEC_CR31 0x1F +#define AB8500_CODEC_CR32 0x20 +#define AB8500_CODEC_CR33 0x21 +#define AB8500_CODEC_CR34 0x22 +#define AB8500_CODEC_CR35 0x23 +#define AB8500_CODEC_CR36 0x24 +#define AB8500_CODEC_CR37 0x25 +#define AB8500_CODEC_CR38 0x26 +#define AB8500_CODEC_CR39 0x27 +#define AB8500_CODEC_CR40 0x28 +#define AB8500_CODEC_CR41 0x29 +#define AB8500_CODEC_CR42 0x2A +#define AB8500_CODEC_CR43 0x2B +#define AB8500_CODEC_CR44 0x2C +#define AB8500_CODEC_CR45 0x2D +#define AB8500_CODEC_CR46 0x2E +#define AB8500_CODEC_CR47 0x2F +#define AB8500_CODEC_CR48 0x30 +#define AB8500_CODEC_CR49 0x31 +#define AB8500_CODEC_CR50 0x32 +#define AB8500_CODEC_CR51 0x33 +#define AB8500_CODEC_CR52 0x34 +#define AB8500_CODEC_CR53 0x35 +#define AB8500_CODEC_CR54 0x36 +#define AB8500_CODEC_CR55 0x37 +#define AB8500_CODEC_CR56 0x38 +#define AB8500_CODEC_CR57 0x39 +#define AB8500_CODEC_CR58 0x3A +#define AB8500_CODEC_CR59 0x3B +#define AB8500_CODEC_CR60 0x3C +#define AB8500_CODEC_CR61 0x3D +#define AB8500_CODEC_CR62 0x3E +#define AB8500_CODEC_CR63 0x3F +#define AB8500_CODEC_CR64 0x40 +#define AB8500_CODEC_CR65 0x41 +#define AB8500_CODEC_CR66 0x42 +#define AB8500_CODEC_CR67 0x43 +#define AB8500_CODEC_CR68 0x44 +#define AB8500_CODEC_CR69 0x45 +#define AB8500_CODEC_CR70 0x46 +#define AB8500_CODEC_CR71 0x47 +#define AB8500_CODEC_CR72 0x48 +#define AB8500_CODEC_CR73 0x49 +#define AB8500_CODEC_CR74 0x4A +#define AB8500_CODEC_CR75 0x4B +#define AB8500_CODEC_CR76 0x4C +#define AB8500_CODEC_CR77 0x4D +#define AB8500_CODEC_CR78 0x4E +#define AB8500_CODEC_CR79 0x4F +#define AB8500_CODEC_CR80 0x50 +#define AB8500_CODEC_CR81 0x51 +#define AB8500_CODEC_CR82 0x52 +#define AB8500_CODEC_CR83 0x53 +#define AB8500_CODEC_CR84 0x54 +#define AB8500_CODEC_CR85 0x55 +#define AB8500_CODEC_CR86 0x56 +#define AB8500_CODEC_CR87 0x57 +#define AB8500_CODEC_CR88 0x58 +#define AB8500_CODEC_CR89 0x59 +#define AB8500_CODEC_CR90 0x5A +#define AB8500_CODEC_CR91 0x5B +#define AB8500_CODEC_CR92 0x5C +#define AB8500_CODEC_CR93 0x5D +#define AB8500_CODEC_CR94 0x5E +#define AB8500_CODEC_CR95 0x5F +#define AB8500_CODEC_CR96 0x60 +#define AB8500_CODEC_CR97 0x61 +#define AB8500_CODEC_CR98 0x62 +#define AB8500_CODEC_CR99 0x63 +#define AB8500_CODEC_CR100 0x64 +#define AB8500_CODEC_CR101 0x65 +#define AB8500_CODEC_CR102 0x66 +#define AB8500_CODEC_CR103 0x67 +#define AB8500_CODEC_CR104 0x68 +#define AB8500_CODEC_CR105 0x69 +#define AB8500_CODEC_CR106 0x6A +#define AB8500_CODEC_CR107 0x6B +#define AB8500_CODEC_CR108 0x6C +#define AB8500_CODEC_CR109 0x6D + +/* CR0-CR0x0000 */ +#define AB8500_CODEC_CR0_POWERUP 7 +#define AB8500_CODEC_CR0_ENAANA 3 + +/* CR1-CR0x0001 */ +#define AB8500_CODEC_CR1_SWRESET 7 + +/* CR2-CR0x0002 */ +#define AB8500_CODEC_CR2_ENAD1 7 +#define AB8500_CODEC_CR2_ENAD2 6 +#define AB8500_CODEC_CR2_ENAD3 5 +#define AB8500_CODEC_CR2_ENAD4 4 +#define AB8500_CODEC_CR2_ENAD5 3 +#define AB8500_CODEC_CR2_ENAD6 2 + +/* CR3-CR0x0003 */ +#define AB8500_CODEC_CR3_ENDA1 7 +#define AB8500_CODEC_CR3_ENDA2 6 +#define AB8500_CODEC_CR3_ENDA3 5 +#define AB8500_CODEC_CR3_ENDA4 4 +#define AB8500_CODEC_CR3_ENDA5 3 +#define AB8500_CODEC_CR3_ENDA6 2 + +/* CR4-CR0x0004 */ +#define AB8500_CODEC_CR4_LOWPOWHS 7 +#define AB8500_CODEC_CR4_LOWPOWDACHS 5 +#define AB8500_CODEC_CR4_LOWPOWEAR 4 +#define AB8500_CODEC_CR4_EAR_SEL_CM 2 +#define AB8500_CODEC_CR4_HS_HP_DIS 1 +#define AB8500_CODEC_CR4_EAR_HP_DIS 0 + +/* CR5-CR0x0005 */ +#define AB8500_CODEC_CR5_ENMIC1 7 +#define AB8500_CODEC_CR5_ENMIC2 6 +#define AB8500_CODEC_CR5_ENLINL 5 +#define AB8500_CODEC_CR5_ENLINR 4 +#define AB8500_CODEC_CR5_MUTMIC1 3 +#define AB8500_CODEC_CR5_MUTMIC2 2 +#define AB8500_CODEC_CR5_MUTELINL 1 +#define AB8500_CODEC_CR5_MUTELINR 0 + +/* CR6-CR0x0006 */ +#define AB8500_CODEC_CR6_ENDMIC1 7 +#define AB8500_CODEC_CR6_ENDMIC2 6 +#define AB8500_CODEC_CR6_ENDMIC3 5 +#define AB8500_CODEC_CR6_ENDMIC4 4 +#define AB8500_CODEC_CR6_ENDMIC5 3 +#define AB8500_CODEC_CR6_ENDMIC6 2 + +/* CR7-CR0x0007 */ +#define AB8500_CODEC_CR7_MIC1SEL 7 +#define AB8500_CODEC_CR7_LINRSEL 6 +#define AB8500_CODEC_CR7_ENDRVHSL 5 +#define AB8500_CODEC_CR7_ENDRVHSR 4 +#define AB8500_CODEC_CR7_ENADCMIC 2 +#define AB8500_CODEC_CR7_ENADCLINL 1 +#define AB8500_CODEC_CR7_ENADCLINR 0 + +/* CR8-CR0x0008 */ +#define AB8500_CODEC_CR8_CP_DIS_PLDWN 7 +#define AB8500_CODEC_CR8_ENEAR 6 +#define AB8500_CODEC_CR8_ENHSL 5 +#define AB8500_CODEC_CR8_ENHSR 4 +#define AB8500_CODEC_CR8_ENHFL 3 +#define AB8500_CODEC_CR8_ENHFR 2 +#define AB8500_CODEC_CR8_ENVIBL 1 +#define AB8500_CODEC_CR8_ENVIBR 0 + +/* CR9-CR0x0009 */ +#define AB8500_CODEC_CR9_ENADACEAR 6 +#define AB8500_CODEC_CR9_ENADACHSL 5 +#define AB8500_CODEC_CR9_ENADACHSR 4 +#define AB8500_CODEC_CR9_ENADACHFL 3 +#define AB8500_CODEC_CR9_ENADACHFR 2 +#define AB8500_CODEC_CR9_ENADACVIBL 1 +#define AB8500_CODEC_CR9_ENADACVIBR 0 + +/* CR10-CR0x000A */ +#define AB8500_CODEC_CR10_MUTEEAR 6 +#define AB8500_CODEC_CR10_MUTEHSL 5 +#define AB8500_CODEC_CR10_MUTEHSR 4 +#define AB8500_CODEC_CR10_MUTEHFL 3 +#define AB8500_CODEC_CR10_MUTEHFR 2 +#define AB8500_CODEC_CR10_MUTEVIBL 1 +#define AB8500_CODEC_CR10_MUTEVIBR 0 + +/* CR11-CR0x000B */ +#define AB8500_CODEC_CR11_ENSHORTPWD 7 +#define AB8500_CODEC_CR11_EARSHORTDIS 6 +#define AB8500_CODEC_CR11_HSLSHORTDIS 5 +#define AB8500_CODEC_CR11_HSRSHORTDIS 4 +#define AB8500_CODEC_CR11_HFLSHORTDIS 3 +#define AB8500_CODEC_CR11_HFRSHORTDIS 2 +#define AB8500_CODEC_CR11_VIBLSHORTDIS 1 +#define AB8500_CODEC_CR11_VIBRSHORTDIS 0 + +/* CR12-CR0x000C */ +#define AB8500_CODEC_CR12_ENCPHS 7 +#define AB8500_CODEC_CR12_HSAUTOTIME 4 +#define AB8500_CODEC_CR12_HSAUTOENSEL 1 +#define AB8500_CODEC_CR12_HSAUTOEN 0 + +/* CR13-CR0x000D */ +#define AB8500_CODEC_CR13_ENVDET_HTHRESH 4 +#define AB8500_CODEC_CR13_ENVDET_LTHRESH 0 + +/* CR14-CR0x000E */ +#define AB8500_CODEC_CR14_SMPSLVEN 7 +#define AB8500_CODEC_CR14_ENVDETSMPSEN 6 +#define AB8500_CODEC_CR14_CPLVEN 5 +#define AB8500_CODEC_CR14_ENVDETCPEN 4 +#define AB8500_CODEC_CR14_ENVDET_TIME 0 + +/* CR15-CR0x000F */ +#define AB8500_CODEC_CR15_PWMTOVIBL 7 +#define AB8500_CODEC_CR15_PWMTOVIBR 6 +#define AB8500_CODEC_CR15_PWMLCTRL 5 +#define AB8500_CODEC_CR15_PWMRCTRL 4 +#define AB8500_CODEC_CR15_PWMNLCTRL 3 +#define AB8500_CODEC_CR15_PWMPLCTRL 2 +#define AB8500_CODEC_CR15_PWMNRCTRL 1 +#define AB8500_CODEC_CR15_PWMPRCTRL 0 + +/* CR16-CR0x0010 */ +#define AB8500_CODEC_CR16_PWMNLPOL 7 +#define AB8500_CODEC_CR16_PWMNLDUTYCYCLE 0 + +/* CR17-CR0x0011 */ +#define AB8500_CODEC_CR17_PWMPLPOL 7 +#define AB8500_CODEC_CR17_PWMLPDUTYCYCLE 0 + +/* CR18-CR0x0012 */ +#define AB8500_CODEC_CR18_PWMNRPOL 7 +#define AB8500_CODEC_CR18_PWMNRDUTYCYCLE 0 + +/* CR19-CR0x0013 */ +#define AB8500_CODEC_CR19_PWMPRPOL 7 +#define AB8500_CODEC_CR19_PWMRPDUTYCYCLE 0 + +/* CR20-CR0x0014 */ +#define AB8500_CODEC_CR20_EN_SE_MIC1 7 +#define AB8500_CODEC_CR20_MIC1_GAIN 0 + +/* CR21-CR0x0015 */ +#define AB8500_CODEC_CR21_EN_SE_MIC2 7 +#define AB8500_CODEC_CR21_MIC2_GAIN 0 + +/* CR22-CR0x0016 */ +#define AB8500_CODEC_CR22_HSL_GAIN 5 +#define AB8500_CODEC_CR22_LINL_GAIN 0 + +/* CR23-CR0x0017 */ +#define AB8500_CODEC_CR23_HSR_GAIN 5 +#define AB8500_CODEC_CR23_LINR_GAIN 0 + +/* CR24-CR0x0018 */ +#define AB8500_CODEC_CR24_LINTOHSL_GAIN 0 + +/* CR25-CR0x0019 */ +#define AB8500_CODEC_CR25_LINTOHSR_GAIN 0 + +/* CR26-CR0x001A */ +#define AB8500_CODEC_CR26_AD1NH 7 +#define AB8500_CODEC_CR26_AD2NH 6 +#define AB8500_CODEC_CR26_AD3NH 5 +#define AB8500_CODEC_CR26_AD4NH 4 +#define AB8500_CODEC_CR26_AD1_VOICE 3 +#define AB8500_CODEC_CR26_AD2_VOICE 2 +#define AB8500_CODEC_CR26_AD3_VOICE 1 +#define AB8500_CODEC_CR26_AD4_VOICE 0 + +/* CR27-CR0x001B */ +#define AB8500_CODEC_CR27_EN_MASTGEN 7 +#define AB8500_CODEC_CR27_IF1_BITCLK_OSR 5 +#define AB8500_CODEC_CR27_ENFS_BITCLK1 4 +#define AB8500_CODEC_CR27_IF0_BITCLK_OSR 1 +#define AB8500_CODEC_CR27_ENFS_BITCLK0 0 + +/* CR28-CR0x001C */ +#define AB8500_CODEC_CR28_FSYNC0P 6 +#define AB8500_CODEC_CR28_BITCLK0P 5 +#define AB8500_CODEC_CR28_IF0DEL 4 +#define AB8500_CODEC_CR28_IF0FORMAT 2 +#define AB8500_CODEC_CR28_IF0WL 0 + +/* CR29-CR0x001D */ +#define AB8500_CODEC_CR29_IF0DATOIF1AD 7 +#define AB8500_CODEC_CR29_IF0CKTOIF1CK 6 +#define AB8500_CODEC_CR29_IF1MASTER 5 +#define AB8500_CODEC_CR29_IF1DATOIF0AD 3 +#define AB8500_CODEC_CR29_IF1CKTOIF0CK 2 +#define AB8500_CODEC_CR29_IF0MASTER 1 +#define AB8500_CODEC_CR29_IF0BFIFOEN 0 + +/* CR30-CR0x001E */ +#define AB8500_CODEC_CR30_FSYNC1P 6 +#define AB8500_CODEC_CR30_BITCLK1P 5 +#define AB8500_CODEC_CR30_IF1DEL 4 +#define AB8500_CODEC_CR30_IF1FORMAT 2 +#define AB8500_CODEC_CR30_IF1WL 0 + +/* CR31-CR0x001F */ +#define AB8500_CODEC_CR31_ADOTOSLOT1 4 +#define AB8500_CODEC_CR31_ADOTOSLOT0 0 + +/* CR32-CR0x0020 */ +#define AB8500_CODEC_CR32_ADOTOSLOT3 4 +#define AB8500_CODEC_CR32_ADOTOSLOT2 0 + +/* CR33-CR0x0021 */ +#define AB8500_CODEC_CR33_ADOTOSLOT5 4 +#define AB8500_CODEC_CR33_ADOTOSLOT4 0 + +/* CR34-CR0x0022 */ +#define AB8500_CODEC_CR34_ADOTOSLOT7 4 +#define AB8500_CODEC_CR34_ADOTOSLOT6 0 + +/* CR35-CR0x0023 */ +#define AB8500_CODEC_CR35_ADOTOSLOT9 4 +#define AB8500_CODEC_CR35_ADOTOSLOT8 0 + +/* CR36-CR0x0024 */ +#define AB8500_CODEC_CR36_ADOTOSLOT11 4 +#define AB8500_CODEC_CR36_ADOTOSLOT10 0 + +/* CR37-CR0x0025 */ +#define AB8500_CODEC_CR37_ADOTOSLOT13 4 +#define AB8500_CODEC_CR37_ADOTOSLOT12 0 + +/* CR38-CR0x0026 */ +#define AB8500_CODEC_CR38_ADOTOSLOT15 4 +#define AB8500_CODEC_CR38_ADOTOSLOT14 0 + +/* CR39-CR0x0027 */ +#define AB8500_CODEC_CR39_ADOTOSLOT17 4 +#define AB8500_CODEC_CR39_ADOTOSLOT16 0 + +/* CR40-CR0x0028 */ +#define AB8500_CODEC_CR40_ADOTOSLOT19 4 +#define AB8500_CODEC_CR40_ADOTOSLOT18 0 + +/* CR41-CR0x0029 */ +#define AB8500_CODEC_CR41_ADOTOSLOT21 4 +#define AB8500_CODEC_CR41_ADOTOSLOT20 0 + +/* CR42-CR0x002A */ +#define AB8500_CODEC_CR42_ADOTOSLOT23 4 +#define AB8500_CODEC_CR42_ADOTOSLOT22 0 + +/* CR43-CR0x002B */ +#define AB8500_CODEC_CR43_ADOTOSLOT25 4 +#define AB8500_CODEC_CR43_ADOTOSLOT24 0 + +/* CR44-CR0x002C */ +#define AB8500_CODEC_CR44_ADOTOSLOT27 4 +#define AB8500_CODEC_CR44_ADOTOSLOT26 0 + +/* CR45-CR0x002D */ +#define AB8500_CODEC_CR45_ADOTOSLOT29 4 +#define AB8500_CODEC_CR45_ADOTOSLOT28 0 + +/* CR46-CR0x002E */ +#define AB8500_CODEC_CR46_ADOTOSLOT31 4 +#define AB8500_CODEC_CR46_ADOTOSLOT30 0 + +/* CR47-CR0x002F */ +#define AB8500_CODEC_CR47_HIZ_SL7 7 +#define AB8500_CODEC_CR47_HIZ_SL6 6 +#define AB8500_CODEC_CR47_HIZ_SL5 5 +#define AB8500_CODEC_CR47_HIZ_SL4 4 +#define AB8500_CODEC_CR47_HIZ_SL3 3 +#define AB8500_CODEC_CR47_HIZ_SL2 2 +#define AB8500_CODEC_CR47_HIZ_SL1 1 +#define AB8500_CODEC_CR47_HIZ_SL0 0 + +/* CR48-CR0x0030 */ +#define AB8500_CODEC_CR48_HIZ_SL15 7 +#define AB8500_CODEC_CR48_HIZ_SL14 6 +#define AB8500_CODEC_CR48_HIZ_SL13 5 +#define AB8500_CODEC_CR48_HIZ_SL12 4 +#define AB8500_CODEC_CR48_HIZ_SL11 3 +#define AB8500_CODEC_CR48_HIZ_SL10 2 +#define AB8500_CODEC_CR48_HIZ_SL9 1 +#define AB8500_CODEC_CR48_HIZ_SL8 0 + +/* CR49-CR0x0031 */ +#define AB8500_CODEC_CR49_HIZ_SL23 7 +#define AB8500_CODEC_CR49_HIZ_SL22 6 +#define AB8500_CODEC_CR49_HIZ_SL21 5 +#define AB8500_CODEC_CR49_HIZ_SL20 4 +#define AB8500_CODEC_CR49_HIZ_SL19 3 +#define AB8500_CODEC_CR49_HIZ_SL18 2 +#define AB8500_CODEC_CR49_HIZ_SL17 1 +#define AB8500_CODEC_CR49_HIZ_SL16 0 + +/* CR50-CR0x0032 */ +#define AB8500_CODEC_CR50_HIZ_SL31 7 +#define AB8500_CODEC_CR50_HIZ_SL30 6 +#define AB8500_CODEC_CR50_HIZ_SL29 5 +#define AB8500_CODEC_CR50_HIZ_SL28 4 +#define AB8500_CODEC_CR50_HIZ_SL27 3 +#define AB8500_CODEC_CR50_HIZ_SL26 2 +#define AB8500_CODEC_CR50_HIZ_SL25 1 +#define AB8500_CODEC_CR50_HIZ_SL24 0 + +/* CR51-CR0x0033 */ +#define AB8500_CODEC_CR51_DA12_VOICE 7 +#define AB8500_CODEC_CR51_SLDAI1TOSLADO1 5 +#define AB8500_CODEC_CR51_SLTODA1 0 + +/* CR52-CR0x0034 */ +#define AB8500_CODEC_CR52_SLDAI1TOSLADO2 5 +#define AB8500_CODEC_CR52_SLTODA2 0 + +/* CR53-CR0x0035 */ +#define AB8500_CODEC_CR53_DA34_VOICE 7 +#define AB8500_CODEC_CR53_SLDAI1TOSLADO3 5 +#define AB8500_CODEC_CR53_SLTODA3 0 + +/* CR54-CR0x0036 */ +#define AB8500_CODEC_CR54_SLDAI1TOSLADO4 5 +#define AB8500_CODEC_CR54_SLTODA4 0 + +/* CR55-CR0x0037 */ +#define AB8500_CODEC_CR55_DA56_VOICE 7 +#define AB8500_CODEC_CR55_SLDAI1TOSLADO5 5 +#define AB8500_CODEC_CR55_SLTODA5 0 + +/* CR56-CR0x0038 */ +#define AB8500_CODEC_CR56_SLDAI1TOSLADO6 5 +#define AB8500_CODEC_CR56_SLTODA6 0 + +/* CR57-CR0x0039 */ +#define AB8500_CODEC_CR57_BFIFULL_MSK 6 +#define AB8500_CODEC_CR57_BFIEMPT_MSK 5 +#define AB8500_CODEC_CR57_DACHAN_MSK 4 +#define AB8500_CODEC_CR57_GAIN_MSK 3 +#define AB8500_CODEC_CR57_DSPAD_MSK 2 +#define AB8500_CODEC_CR57_DSPDA_MSK 1 +#define AB8500_CODEC_CR57_STFIR_MSK 0 + +/* CR58-CR0x003A */ +#define AB8500_CODEC_CR58_BFIFULL_EV 6 +#define AB8500_CODEC_CR58_BFIEMPT_EV 5 +#define AB8500_CODEC_CR58_DACHAN_EV 4 +#define AB8500_CODEC_CR58_GAIN_EV 3 +#define AB8500_CODEC_CR58_DSPAD_EV 2 +#define AB8500_CODEC_CR58_DSPDA_EV 1 +#define AB8500_CODEC_CR58_STFIR_EV 0 + +/* CR59-CR0x003B */ +#define AB8500_CODEC_CR59_VSSREADY_MSK 7 +#define AB8500_CODEC_CR59_SHRTVIBL_MSK 6 +#define AB8500_CODEC_CR59_SHRTVIBR_MSK 5 +#define AB8500_CODEC_CR59_SHRTHFL_MSK 4 +#define AB8500_CODEC_CR59_SHRTHFR_MSK 3 +#define AB8500_CODEC_CR59_SHRTHSL_MSK 2 +#define AB8500_CODEC_CR59_SHRTHSR_MSK 1 +#define AB8500_CODEC_CR59_SHRTEAR_MSK 0 + +/* CR60-CR0x003C */ +#define AB8500_CODEC_CR60_VSSREADY_EV 7 +#define AB8500_CODEC_CR60_SHRTVIBL_EV 6 +#define AB8500_CODEC_CR60_SHRTVIBR_EV 5 +#define AB8500_CODEC_CR60_SHRTHFL_EV 4 +#define AB8500_CODEC_CR60_SHRTHFR_EV 3 +#define AB8500_CODEC_CR60_SHRTHSL_EV 2 +#define AB8500_CODEC_CR60_SHRTHSR_EV 1 +#define AB8500_CODEC_CR60_SHRTEAR_EV 0 + +/* CR61-CR0x003D */ +#define AB8500_CODEC_CR61_REVISION 2 +#define AB8500_CODEC_CR61_FADE_SPEED 0 + +/* CR62-CR0x003E */ +#define AB8500_CODEC_CR62_DMIC1SINC3 5 +#define AB8500_CODEC_CR62_DMIC2SINC3 4 +#define AB8500_CODEC_CR62_DMIC3SINC3 3 +#define AB8500_CODEC_CR62_DMIC4SINC3 2 +#define AB8500_CODEC_CR62_DMIC5SINC3 1 +#define AB8500_CODEC_CR62_DMIC6SINC3 0 + +/* CR63-CR0x003F */ +#define AB8500_CODEC_CR63_DATOHSLEN 7 +#define AB8500_CODEC_CR63_DATOHSREN 6 +#define AB8500_CODEC_CR63_AD1SEL 5 +#define AB8500_CODEC_CR63_AD2SEL 4 +#define AB8500_CODEC_CR63_AD3SEL 3 +#define AB8500_CODEC_CR63_AD5SEL 2 +#define AB8500_CODEC_CR63_AD6SEL 1 +#define AB8500_CODEC_CR63_ANCSEL 0 + +/* CR64-CR0x0040 */ +#define AB8500_CODEC_CR64_DATOHFREN 7 +#define AB8500_CODEC_CR64_DATOHFLEN 6 +#define AB8500_CODEC_CR64_HFRSEL 5 +#define AB8500_CODEC_CR64_HFLSEL 4 +#define AB8500_CODEC_CR64_STFIR1SEL 2 +#define AB8500_CODEC_CR64_STFIR2SEL 0 + +/* CR65-CR0x0041 */ +#define AB8500_CODEC_CR65_FADEDIS_AD1 6 +#define AB8500_CODEC_CR65_AD1GAIN 0 + +/* CR66-CR0x0042 */ +#define AB8500_CODEC_CR66_FADEDIS_AD2 6 +#define AB8500_CODEC_CR66_AD2GAIN 0 + +/* CR67-CR0x0043 */ +#define AB8500_CODEC_CR67_FADEDIS_AD3 6 +#define AB8500_CODEC_CR67_AD3GAIN 0 + +/* CR68-CR0x0044 */ +#define AB8500_CODEC_CR68_FADEDIS_AD4 6 +#define AB8500_CODEC_CR68_AD4GAIN 0 + +/* CR69-CR0x0045 */ +#define AB8500_CODEC_CR69_FADEDIS_AD5 6 +#define AB8500_CODEC_CR69_AD5GAIN 0 + +/* CR70-CR0x0046 */ +#define AB8500_CODEC_CR70_FADEDIS_AD6 6 +#define AB8500_CODEC_CR70_AD6GAIN 0 + +/* CR71-CR0x0047 */ +#define AB8500_CODEC_CR71_FADEDIS_DA1 6 +#define AB8500_CODEC_CR71_DA1GAIN 0 + +/* CR72-CR0x0048 */ +#define AB8500_CODEC_CR72_FADEDIS_DA2 6 +#define AB8500_CODEC_CR72_DA2GAIN 0 + +/* CR73-CR0x0049 */ +#define AB8500_CODEC_CR73_FADEDIS_DA3 6 +#define AB8500_CODEC_CR73_DA3GAIN 0 + +/* CR74-CR0x004A */ +#define AB8500_CODEC_CR74_FADEDIS_DA4 6 +#define AB8500_CODEC_CR74_DA4GAIN 0 + +/* CR75-CR0x004B */ +#define AB8500_CODEC_CR75_FADEDIS_DA5 6 +#define AB8500_CODEC_CR75_DA5GAIN 0 + +/* CR76-CR0x004C */ +#define AB8500_CODEC_CR76_FADEDIS_DA6 6 +#define AB8500_CODEC_CR76_DA6GAIN 0 + +/* CR77-CR0x004D */ +#define AB8500_CODEC_CR77_FADEDIS_AD1L 6 +#define AB8500_CODEC_CR77_AD1LBGAIN 0 + +/* CR78-CR0x004E */ +#define AB8500_CODEC_CR78_FADEDIS_AD2L 6 +#define AB8500_CODEC_CR78_AD2LBGAIN 0 + +/* CR79-CR0x004F */ +#define AB8500_CODEC_CR79_HSSINC1 7 +#define AB8500_CODEC_CR79_FADEDIS_HSL 4 +#define AB8500_CODEC_CR79_HSLDGAIN 0 + +/* CR80-CR0x0050 */ +#define AB8500_CODEC_CR80_FADEDIS_HSR 4 +#define AB8500_CODEC_CR80_HSRDGAIN 0 + +/* CR81-CR0x0051 */ +#define AB8500_CODEC_CR81_STFIR1GAIN 0 + +/* CR82-CR0x0052 */ +#define AB8500_CODEC_CR82_STFIR2GAIN 0 + +/* CR83-CR0x0053 */ +#define AB8500_CODEC_CR83_ENANC 2 +#define AB8500_CODEC_CR83_ANCIIRINIT 1 +#define AB8500_CODEC_CR83_ANCFIRUPDATE 0 + +/* CR84-CR0x0054 */ +#define AB8500_CODEC_CR84_ANCINSHIFT 0 + +/* CR85-CR0x0055 */ +#define AB8500_CODEC_CR85_ANCFIROUTSHIFT 0 + +/* CR86-CR0x0056 */ +#define AB8500_CODEC_CR86_ANCSHIFTOUT 0 + +/* CR87-CR0x0057 */ +#define AB8500_CODEC_CR87_ANCFIRCOEFF_MSB 0 + +/* CR88-CR0x0058 */ +#define AB8500_CODEC_CR88_ANCFIRCOEFF_LSB 0 + +/* CR89-CR0x0059 */ +#define AB8500_CODEC_CR89_ANCIIRCOEFF_MSB 0 + +/* CR90-CR0x005A */ +#define AB8500_CODEC_CR90_ANCIIRCOEFF_LSB 0 + +/* CR91-CR0x005B */ +#define AB8500_CODEC_CR91_ANCWARPDEL_MSB 0 + +/* CR92-CR0x005C */ +#define AB8500_CODEC_CR92_ANCWARPDEL_LSB 0 + +/* CR93-CR0x005D */ +#define AB8500_CODEC_CR93_ANCFIRPEAK_MSB 0 + +/* CR94-CR0x005E */ +#define AB8500_CODEC_CR94_ANCFIRPEAK_LSB 0 + +/* CR95-CR0x005F */ +#define AB8500_CODEC_CR95_ANCIIRPEAK_MSB 0 + +/* CR96-CR0x0060 */ +#define AB8500_CODEC_CR96_ANCIIRPEAK_LSB 0 + +/* CR97-CR0x0061 */ +#define AB8500_CODEC_CR97_STFIR_SET 7 +#define AB8500_CODEC_CR97_STFIR_ADDR 0 + +/* CR98-CR0x0062 */ +#define AB8500_CODEC_CR98_STFIR_COEFF_MSB 0 + +/* CR99-CR0x0063 */ +#define AB8500_CODEC_CR99_STFIR_COEFF_LSB 0 + +/* CR100-CR0x0064 */ +#define AB8500_CODEC_CR100_ENSTFIRS 2 +#define AB8500_CODEC_CR100_STFIRSTOIF1 1 +#define AB8500_CODEC_CR100_STFIR_BUSY 0 + +/* CR101-CR0x0065 */ +#define AB8500_CODEC_CR101_PARLHF 7 +#define AB8500_CODEC_CR101_PARLVIB 6 +#define AB8500_CODEC_CR101_CLASSDVIBLSWAPEN 3 +#define AB8500_CODEC_CR101_CLASSDVIBRSWAPEN 2 +#define AB8500_CODEC_CR101_CLASSDHFLSWAPEN 1 +#define AB8500_CODEC_CR101_CLASSDHFRSWAPEN 0 + +/* CR102-CR0x0066 */ +#define AB8500_CODEC_CR102_CLASSD_FIRBYP 4 +#define AB8500_CODEC_CR102_CLASSD_HIGHVOLEN 0 + +/* CR103-CR0x0067 */ +#define AB8500_CODEC_CR103_CLASSD_DITHERHPGAIN 4 +#define AB8500_CODEC_CR103_CLASSD_DITHERWGAIN 0 + +/* CR104-CR0x0068 */ +#define AB8500_CODEC_CR104_BFIFOINT 0 + +/* CR105-CR0x0069 */ +#define AB8500_CODEC_CR105_BFIFOTX 0 + +/* CR106-CR0x006A */ +#define AB8500_CODEC_CR106_BFIFOFSEXT 4 +#define AB8500_CODEC_CR106_BFIFOMSK 2 +#define AB8500_CODEC_CR106_BFIFOMSTR 1 +#define AB8500_CODEC_CR106_BFIFOSTRT 0 + +/* CR107-CR0x006B */ +#define AB8500_CODEC_CR107_BFIFOSAMPNR 0 + +/* CR108-CR0x006C */ +#define AB8500_CODEC_CR108_BFIFOWAKEUP 0 + +/* CR109-CR0x006D */ +#define AB8500_CODEC_CR109_BFIFOSAMPLES 0 + +/* For SetVolume API*/ +#define AB8500_CODEC_MAX_VOLUME 100 + +/* Analog MIC1 & MIC2 */ +#define AB8500_CODEC_MIC_VOLUME_MAX 31 +#define AB8500_CODEC_MIC_VOLUME_MEDIUM 15 +#define AB8500_CODEC_MIC_VOLUME_MIN 0 + +/* Line-in */ +#define AB8500_CODEC_LINEIN_VOLUME_MAX 31 +#define AB8500_CODEC_LINEIN_VOLUME_MEDIUM 15 +#define AB8500_CODEC_LINEIN_VOLUME_MIN 0 + +/* HeadSet */ +#define AB8500_CODEC_HEADSET_VOLUME_MAX 0 +#define AB8500_CODEC_HEADSET_VOLUME_MEDIUM 3 +#define AB8500_CODEC_HEADSET_VOLUME_MIN 7 + +/* HeadSet Digital */ +#define AB8500_CODEC_HEADSET_D_VOLUME_MAX 0 +#define AB8500_CODEC_HEADSET_D_VOLUME_MEDIUM 7 +#define AB8500_CODEC_HEADSET_D_VOLUME_MIN 15 +#define AB8500_CODEC_HEADSET_D_VOLUME_0DB 8 + +/* Digital AD Path */ +#define AB8500_CODEC_AD_D_VOLUME_MAX 0 +#define AB8500_CODEC_AD_D_VOLUME_MEDIUM 31 +#define AB8500_CODEC_AD_D_VOLUME_MIN 63 + +/* Digital DA Path */ +#define AB8500_CODEC_DA_D_VOLUME_MAX 0 +#define AB8500_CODEC_DA_D_VOLUME_MEDIUM 31 +#define AB8500_CODEC_DA_D_VOLUME_MIN 63 + +/* EarPiece Digital */ +#define AB8500_CODEC_EARPIECE_D_VOLUME_MAX 0 +#define AB8500_CODEC_EARPIECE_D_VOLUME_MEDIUM 7 +#define AB8500_CODEC_EARPIECE_D_VOLUME_MIN 15 + +/* AD1 loopback to HFL & HFR Digital */ +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MAX 0 +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MEDIUM 31 +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MIN 63 + +/* Line-in to HSL & HSR */ +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX 0 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MEDIUM 9 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN 18 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN 19 + +/* Vibrator */ +#define AB8500_CODEC_VIBRATOR_VOLUME_MAX 100 +#define AB8500_CODEC_VIBRATOR_VOLUME_MEDIUM 50 +#define AB8500_CODEC_VIBRATOR_VOLUME_MIN 0 + +/* CR0 - 7 */ +typedef enum { + AB8500_CODEC_CR0_POWERUP_OFF, + AB8500_CODEC_CR0_POWERUP_ON +} t_ab8500_codec_cr0_powerup; + +/* CR0 - 3 */ +typedef enum { + AB8500_CODEC_CR0_ENAANA_OFF, + AB8500_CODEC_CR0_ENAANA_ON +} t_ab8500_codec_cr0_enaana; + +/* CR1 - 7 */ +typedef enum { + AB8500_CODEC_CR1_SWRESET_DISABLED, + AB8500_CODEC_CR1_SWRESET_ENABLED +} t_ab8500_codec_cr1_swreset; + +/* CR2 - 7 */ +typedef enum { + AB8500_CODEC_CR2_ENAD1_DISABLED, + AB8500_CODEC_CR2_ENAD1_ENABLED +} t_ab8500_codec_cr2_enad1; + +/* CR2 - 6 */ +typedef enum { + AB8500_CODEC_CR2_ENAD2_DISABLED, + AB8500_CODEC_CR2_ENAD2_ENABLED +} t_ab8500_codec_cr2_enad2; + +/* CR2 - 5 */ +typedef enum { + AB8500_CODEC_CR2_ENAD3_DISABLED, + AB8500_CODEC_CR2_ENAD3_ENABLED +} t_ab8500_codec_cr2_enad3; + +/* CR2 - 4 */ +typedef enum { + AB8500_CODEC_CR2_ENAD4_DISABLED, + AB8500_CODEC_CR2_ENAD4_ENABLED +} t_ab8500_codec_cr2_enad4; + +/* CR2 - 3 */ +typedef enum { + AB8500_CODEC_CR2_ENAD5_DISABLED, + AB8500_CODEC_CR2_ENAD5_ENABLED +} t_ab8500_codec_cr2_enad5; + +/* CR2 - 2 */ +typedef enum { + AB8500_CODEC_CR2_ENAD6_DISABLED, + AB8500_CODEC_CR2_ENAD6_ENABLED +} t_ab8500_codec_cr2_enad6; + +/* CR3 - 7 */ +typedef enum { + AB8500_CODEC_CR3_ENDA1_DISABLED, + AB8500_CODEC_CR3_ENDA1_ENABLED +} t_ab8500_codec_cr3_enda1; + +/* CR3 - 6 */ +typedef enum { + AB8500_CODEC_CR3_ENDA2_DISABLED, + AB8500_CODEC_CR3_ENDA2_ENABLED +} t_ab8500_codec_cr3_enda2; + +/* CR3 - 5 */ +typedef enum { + AB8500_CODEC_CR3_ENDA3_DISABLED, + AB8500_CODEC_CR3_ENDA3_ENABLED +} t_ab8500_codec_cr3_enda3; + +/* CR3 - 4 */ +typedef enum { + AB8500_CODEC_CR3_ENDA4_DISABLED, + AB8500_CODEC_CR3_ENDA4_ENABLED +} t_ab8500_codec_cr3_enda4; + +/* CR3 - 3 */ +typedef enum { + AB8500_CODEC_CR3_ENDA5_DISABLED, + AB8500_CODEC_CR3_ENDA5_ENABLED +} t_ab8500_codec_cr3_enda5; + +/* CR3 - 2 */ +typedef enum { + AB8500_CODEC_CR3_ENDA6_DISABLED, + AB8500_CODEC_CR3_ENDA6_ENABLED +} t_ab8500_codec_cr3_enda6; + +/* CR4 - 7 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWHS_NORMAL, + AB8500_CODEC_CR4_LOWPOWHS_LP +} t_ab8500_codec_cr4_lowpowhs; + +/* CR4 - 6:5 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWDACHS_NORMAL, + AB8500_CODEC_CR4_LOWPOWDACHS_DRIVERS_LP, + AB8500_CODEC_CR4_LOWPOWDACHS_LP, + AB8500_CODEC_CR4_LOWPOWDACHS_BOTH_LP +} t_ab8500_codec_cr4_lowpowdachs; + +/* CR4 - 4 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWEAR_NORMAL, + AB8500_CODEC_CR4_LOWPOWEAR_LP +} t_ab8500_codec_cr4_lowpowear; + +/* CR4 - 3:2 */ +typedef enum { + AB8500_CODEC_CR4_EAR_SEL_CM_0_95V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_1V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_27V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_58V +} t_ab8500_codec_cr4_ear_sel_cm; + +/* CR4 - 1 */ +typedef enum { + AB8500_CODEC_CR4_HS_HP_DIS_FILTER_ENABLED, + AB8500_CODEC_CR4_HS_HP_DIS_FILTER_DISABLED +} t_ab8500_codec_cr4_hs_hp_dis; + +/* CR4 - 0 */ +typedef enum { + AB8500_CODEC_CR4_EAR_HP_DIS_FILTER_ENABLED, + AB8500_CODEC_CR4_EAR_HP_DIS_FILTER_DISABLED +} t_ab8500_codec_cr4_ear_hp_dis; + +/* CR5 - 7 */ +typedef enum { + AB8500_CODEC_CR5_ENMIC1_DISABLED, + AB8500_CODEC_CR5_ENMIC1_ENABLED +} t_ab8500_codec_cr5_enmic1; + +/* CR5 - 6 */ +typedef enum { + AB8500_CODEC_CR5_ENMIC2_DISABLED, + AB8500_CODEC_CR5_ENMIC2_ENABLED +} t_ab8500_codec_cr5_enmic2; + +/* CR5 - 5 */ +typedef enum { + AB8500_CODEC_CR5_ENLINL_DISABLED, + AB8500_CODEC_CR5_ENLINL_ENABLED +} t_ab8500_codec_cr5_enlinl; + +/* CR5 - 4 */ +typedef enum { + AB8500_CODEC_CR5_ENLINR_DISABLED, + AB8500_CODEC_CR5_ENLINR_ENABLED +} t_ab8500_codec_cr5_enlinr; + +/* CR5 - 3 */ +typedef enum { + AB8500_CODEC_CR5_MUTMIC1_DISABLED, + AB8500_CODEC_CR5_MUTMIC1_ENABLED +} t_ab8500_codec_cr5_mutmic1; + +/* CR5 - 2 */ +typedef enum { + AB8500_CODEC_CR5_MUTMIC2_DISABLED, + AB8500_CODEC_CR5_MUTMIC2_ENABLED +} t_ab8500_codec_cr5_mutmic2; + +/* CR5 - 1 */ +typedef enum { + AB8500_CODEC_CR5_MUTLINL_DISABLED, + AB8500_CODEC_CR5_MUTLINL_ENABLED +} t_ab8500_codec_cr5_mutlinl; + +/* CR5 - 0 */ +typedef enum { + AB8500_CODEC_CR5_MUTLINR_DISABLED, + AB8500_CODEC_CR5_MUTLINR_ENABLED +} t_ab8500_codec_cr5_mutlinr; + +/* CR6 - 7 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC1_DISABLED, + AB8500_CODEC_CR6_ENDMIC1_ENABLED +} t_ab8500_codec_cr6_endmic1; + +/* CR6 - 6 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC2_DISABLED, + AB8500_CODEC_CR6_ENDMIC2_ENABLED +} t_ab8500_codec_cr6_endmic2; + +/* CR6 - 5 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC3_DISABLED, + AB8500_CODEC_CR6_ENDMIC3_ENABLED +} t_ab8500_codec_cr6_endmic3; + +/* CR6 - 4 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC4_DISABLED, + AB8500_CODEC_CR6_ENDMIC4_ENABLED +} t_ab8500_codec_cr6_endmic4; + +/* CR6 - 3 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC5_DISABLED, + AB8500_CODEC_CR6_ENDMIC5_ENABLED +} t_ab8500_codec_cr6_endmic5; + +/* CR6 - 2 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC6_DISABLED, + AB8500_CODEC_CR6_ENDMIC6_ENABLED +} t_ab8500_codec_cr6_endmic6; + +/* CR7 - 7 */ +typedef enum { + AB8500_CODEC_CR7_MIC1SEL_MIC1A, + AB8500_CODEC_CR7_MIC1SEL_MIC1B +} t_ab8500_codec_cr7_mic1sel; + +/* CR7 - 6 */ +typedef enum { + AB8500_CODEC_CR7_LINRSEL_MIC2, + AB8500_CODEC_CR7_LINRSEL_LINR +} t_ab8500_codec_cr7_linrsel; + +/* CR7 - 5 */ +typedef enum { + AB8500_CODEC_CR7_ENDRVHSL_DISABLED, + AB8500_CODEC_CR7_ENDRVHSL_ENABLED +} t_ab8500_codec_cr7_endrvhsl; + +/* CR7 - 4 */ +typedef enum { + AB8500_CODEC_CR7_ENDRVHSR_DISABLED, + AB8500_CODEC_CR7_ENDRVHSR_ENABLED +} t_ab8500_codec_cr7_endrvhsr; + +/* CR7 - 2 */ +typedef enum { + AB8500_CODEC_CR7_ENADCMIC_DISABLED, + AB8500_CODEC_CR7_ENADCMIC_ENABLED +} t_ab8500_codec_cr7_enadcmic; + +/* CR7 - 1 */ +typedef enum { + AB8500_CODEC_CR7_ENADCLINL_DISABLED, + AB8500_CODEC_CR7_ENADCLINL_ENABLED +} t_ab8500_codec_cr7_enadclinl; + +/* CR7 - 0 */ +typedef enum { + AB8500_CODEC_CR7_ENADCLINR_DISABLED, + AB8500_CODEC_CR7_ENADCLINR_ENABLED +} t_ab8500_codec_cr7_enadclinr; + +/* CR8 - 7 */ +typedef enum { + AB8500_CODEC_CR8_CP_DIS_PLDWN_ENABLED, + AB8500_CODEC_CR8_CP_DIS_PLDWN_DISABLED +} t_ab8500_codec_cr8_cp_dis_pldwn; + +/* CR8 - 6 */ +typedef enum { + AB8500_CODEC_CR8_ENEAR_DISABLED, + AB8500_CODEC_CR8_ENEAR_ENABLED +} t_ab8500_codec_cr8_enear; + +/* CR8 - 5 */ +typedef enum { + AB8500_CODEC_CR8_ENHSL_DISABLED, + AB8500_CODEC_CR8_ENHSL_ENABLED +} t_ab8500_codec_cr8_enhsl; + +/* CR8 - 4 */ +typedef enum { + AB8500_CODEC_CR8_ENHSR_DISABLED, + AB8500_CODEC_CR8_ENHSR_ENABLED +} t_ab8500_codec_cr8_enhsr; + +/* CR8 - 3 */ +typedef enum { + AB8500_CODEC_CR8_ENHFL_DISABLED, + AB8500_CODEC_CR8_ENHFL_ENABLED +} t_ab8500_codec_cr8_enhfl; + +/* CR8 - 2 */ +typedef enum { + AB8500_CODEC_CR8_ENHFR_DISABLED, + AB8500_CODEC_CR8_ENHFR_ENABLED +} t_ab8500_codec_cr8_enhfr; + +/* CR8 - 1 */ +typedef enum { + AB8500_CODEC_CR8_ENVIBL_DISABLED, + AB8500_CODEC_CR8_ENVIBL_ENABLED +} t_ab8500_codec_cr8_envibl; + +/* CR8 - 0 */ +typedef enum { + AB8500_CODEC_CR8_ENVIBR_DISABLED, + AB8500_CODEC_CR8_ENVIBR_ENABLED +} t_ab8500_codec_cr8_envibr; + +/* CR9 - 6 */ +typedef enum { + AB8500_CODEC_CR9_ENDACEAR_DISABLED, + AB8500_CODEC_CR9_ENDACEAR_ENABLED +} t_ab8500_codec_cr9_endacear; + +/* CR9 - 5 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHSL_DISABLED, + AB8500_CODEC_CR9_ENDACHSL_ENABLED +} t_ab8500_codec_cr9_endachsl; + +/* CR9 - 4 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHSR_DISABLED, + AB8500_CODEC_CR9_ENDACHSR_ENABLED +} t_ab8500_codec_cr9_endachsr; + +/* CR9 - 3 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHFL_DISABLED, + AB8500_CODEC_CR9_ENDACHFL_ENABLED +} t_ab8500_codec_cr9_endachfl; + +/* CR9 - 2 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHFR_DISABLED, + AB8500_CODEC_CR9_ENDACHFR_ENABLED +} t_ab8500_codec_cr9_endachfr; + +/* CR9 - 1 */ +typedef enum { + AB8500_CODEC_CR9_ENDACVIBL_DISABLED, + AB8500_CODEC_CR9_ENDACVIBL_ENABLED +} t_ab8500_codec_cr9_endacvibl; + +/* CR9 - 0 */ +typedef enum { + AB8500_CODEC_CR9_ENDACVIBR_DISABLED, + AB8500_CODEC_CR9_ENDACVIBR_ENABLED +} t_ab8500_codec_cr9_endacvibr; + +/* CR10 - 6 */ +typedef enum { + AB8500_CODEC_CR10_MUTEEAR_DISABLED, + AB8500_CODEC_CR10_MUTEEAR_ENABLED +} t_ab8500_codec_cr10_muteear; + +/* CR10 - 5 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHSL_DISABLED, + AB8500_CODEC_CR10_MUTEHSL_ENABLED +} t_ab8500_codec_cr10_mutehsl; + +/* CR10 - 4 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHSR_DISABLED, + AB8500_CODEC_CR10_MUTEHSR_ENABLED +} t_ab8500_codec_cr10_mutehsr; + +/* CR10 - 3 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHFL_DISABLED, + AB8500_CODEC_CR10_MUTEHFL_ENABLED +} t_ab8500_codec_cr10_mutehfl; + +/* CR10 - 2 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHFR_DISABLED, + AB8500_CODEC_CR10_MUTEHFR_ENABLED +} t_ab8500_codec_cr10_mutehfr; + +/* CR10 - 1 */ +typedef enum { + AB8500_CODEC_CR10_MUTEVIBL_DISABLED, + AB8500_CODEC_CR10_MUTEVIBL_ENABLED +} t_ab8500_codec_cr10_mutevibl; + +/* CR10 - 0 */ +typedef enum { + AB8500_CODEC_CR10_MUTEVIBR_DISABLED, + AB8500_CODEC_CR10_MUTEVIBR_ENABLED +} t_ab8500_codec_cr10_mutevibr; + +/* CR11 - 7 */ +typedef enum { + AB8500_CODEC_CR11_EARSHORTPWD_DISABLED, + AB8500_CODEC_CR11_EARSHORTPWD_ENABLED +} t_ab8500_codec_cr11_earshortpwd; + +/* CR11 - 6 */ +typedef enum { + AB8500_CODEC_CR11_EARSHORTDIS_ENABLED, + AB8500_CODEC_CR11_EARSHORTDIS_DISABLED +} t_ab8500_codec_cr11_earshortdis; + +/* CR11 - 5 */ +typedef enum { + AB8500_CODEC_CR11_HSLSHORTDIS_ENABLED, + AB8500_CODEC_CR11_HSLSHORTDIS_DISABLED +} t_ab8500_codec_cr11_hslshortdis; + +/* CR11 - 4 */ +typedef enum { + AB8500_CODEC_CR11_HSRSHORTDIS_ENABLED, + AB8500_CODEC_CR11_HSRSHORTDIS_DISABLED +} t_ab8500_codec_cr11_hsrshortdis; + +/* CR11 - 3 */ +typedef enum { + AB8500_CODEC_CR11_HFLSHORTDIS_ENABLED, + AB8500_CODEC_CR11_HFLSHORTDIS_DISABLED +} t_ab8500_codec_cr11_hflshortdis; + +/* CR11 - 2 */ +typedef enum { + AB8500_CODEC_CR11_HFRSHORTDIS_ENABLED, + AB8500_CODEC_CR11_HFRSHORTDIS_DISABLED +} t_ab8500_codec_cr11_hfrshortdis; + +/* CR11 - 1 */ +typedef enum { + AB8500_CODEC_CR11_VIBLSHORTDIS_ENABLED, + AB8500_CODEC_CR11_VIBLSHORTDIS_DISABLED +} t_ab8500_codec_cr11_viblshortdis; + +/* CR11 - 0 */ +typedef enum { + AB8500_CODEC_CR11_VIBRSHORTDIS_ENABLED, + AB8500_CODEC_CR11_VIBRSHORTDIS_DISABLED +} t_ab8500_codec_cr11_vibrshortdis; + +/* CR12 - 7 */ +typedef enum { + AB8500_CODEC_CR12_ENCPHS_DISABLED, + AB8500_CODEC_CR12_ENCPHS_ENABLED +} t_ab8500_codec_cr12_encphs; + +/* CR12 - 6:4 */ +typedef enum { + AB8500_CODEC_CR12_HSAUTOTIME_6_6USEC, + AB8500_CODEC_CR12_HSAUTOTIME_13_3USEC, + AB8500_CODEC_CR12_HSAUTOTIME_26_6USEC, + AB8500_CODEC_CR12_HSAUTOTIME_53_2USEC, + AB8500_CODEC_CR12_HSAUTOTIME_106_4USEC, + AB8500_CODEC_CR12_HSAUTOTIME_212_8USEC, + AB8500_CODEC_CR12_HSAUTOTIME_425_6USEC, + AB8500_CODEC_CR12_HSAUTOTIME_851_2USEC, +} t_ab8500_codec_cr12_hsautotime; + +/* CR12 - 1 */ +typedef enum { + AB8500_CODEC_CR12_HSAUTOENSEL_DISABLED, + AB8500_CODEC_CR12_HSAUTOENSEL_ENABLED +} t_ab8500_codec_cr12_hsautoensel; + +/* CR12 - 0 */ +typedef enum { + AB8500_CODEC_CR12_HSAUTOEN_DISABLED, + AB8500_CODEC_CR12_HSAUTOEN_ENABLED +} t_ab8500_codec_cr12_hsautoen; + +/* CR13 - 7:4 */ +typedef enum { + AB8500_CODEC_CR13_ENVDET_HTHRESH_25, + AB8500_CODEC_CR13_ENVDET_HTHRESH_50, + AB8500_CODEC_CR13_ENVDET_HTHRESH_100, + AB8500_CODEC_CR13_ENVDET_HTHRESH_150, + AB8500_CODEC_CR13_ENVDET_HTHRESH_200, + AB8500_CODEC_CR13_ENVDET_HTHRESH_250, + AB8500_CODEC_CR13_ENVDET_HTHRESH_300, + AB8500_CODEC_CR13_ENVDET_HTHRESH_350, + AB8500_CODEC_CR13_ENVDET_HTHRESH_400, + AB8500_CODEC_CR13_ENVDET_HTHRESH_450, + AB8500_CODEC_CR13_ENVDET_HTHRESH_500, + AB8500_CODEC_CR13_ENVDET_HTHRESH_550, + AB8500_CODEC_CR13_ENVDET_HTHRESH_600, + AB8500_CODEC_CR13_ENVDET_HTHRESH_650, + AB8500_CODEC_CR13_ENVDET_HTHRESH_700, + AB8500_CODEC_CR13_ENVDET_HTHRESH_750 +} t_ab8500_codec_cr13_envdet_hthresh; + +/* CR13 - 3:0 */ +typedef enum { + AB8500_CODEC_CR13_ENVDET_LTHRESH_25, + AB8500_CODEC_CR13_ENVDET_LTHRESH_50, + AB8500_CODEC_CR13_ENVDET_LTHRESH_100, + AB8500_CODEC_CR13_ENVDET_LTHRESH_150, + AB8500_CODEC_CR13_ENVDET_LTHRESH_200, + AB8500_CODEC_CR13_ENVDET_LTHRESH_250, + AB8500_CODEC_CR13_ENVDET_LTHRESH_300, + AB8500_CODEC_CR13_ENVDET_LTHRESH_350, + AB8500_CODEC_CR13_ENVDET_LTHRESH_400, + AB8500_CODEC_CR13_ENVDET_LTHRESH_450, + AB8500_CODEC_CR13_ENVDET_LTHRESH_500, + AB8500_CODEC_CR13_ENVDET_LTHRESH_550, + AB8500_CODEC_CR13_ENVDET_LTHRESH_600, + AB8500_CODEC_CR13_ENVDET_LTHRESH_650, + AB8500_CODEC_CR13_ENVDET_LTHRESH_700, + AB8500_CODEC_CR13_ENVDET_LTHRESH_750 +} t_ab8500_codec_cr13_envdet_lthresh; + +/* CR14 - 7 */ +typedef enum { + AB8500_CODEC_CR14_SMPSLVEN_HIGHVOLTAGE, + AB8500_CODEC_CR14_SMPSLVEN_LOWVOLTAGE +} t_ab8500_codec_cr14_smpslven; + +/* CR14 - 6 */ +typedef enum { + AB8500_CODEC_CR14_ENVDETSMPSEN_DISABLED, + AB8500_CODEC_CR14_ENVDETSMPSEN_ENABLED +} t_ab8500_codec_cr14_envdetsmpsen; + +/* CR14 - 5 */ +typedef enum { + AB8500_CODEC_CR14_CPLVEN_HIGHVOLTAGE, + AB8500_CODEC_CR14_CPLVEN_LOWVOLTAGE +} t_ab8500_codec_cr14_cplven; + +/* CR14 - 4 */ +typedef enum { + AB8500_CODEC_CR14_ENVDETCPEN_DISABLED, + AB8500_CODEC_CR14_ENVDETCPEN_ENABLED +} t_ab8500_codec_cr14_envdetcpen; + +/* CR14 - 3:0 */ +typedef enum { + AB8500_CODEC_CR14_ENVET_TIME_27USEC, + AB8500_CODEC_CR14_ENVET_TIME_53USEC, + AB8500_CODEC_CR14_ENVET_TIME_106USEC, + AB8500_CODEC_CR14_ENVET_TIME_212USEC, + AB8500_CODEC_CR14_ENVET_TIME_424USEC, + AB8500_CODEC_CR14_ENVET_TIME_848USEC, + AB8500_CODEC_CR14_ENVET_TIME_1MSEC, + AB8500_CODEC_CR14_ENVET_TIME_3MSEC, + AB8500_CODEC_CR14_ENVET_TIME_6MSEC, + AB8500_CODEC_CR14_ENVET_TIME_13MSEC, + AB8500_CODEC_CR14_ENVET_TIME_27MSEC, + AB8500_CODEC_CR14_ENVET_TIME_54MSEC, + AB8500_CODEC_CR14_ENVET_TIME_109MSEC, + AB8500_CODEC_CR14_ENVET_TIME_218MSEC, + AB8500_CODEC_CR14_ENVET_TIME_436MSEC, + AB8500_CODEC_CR14_ENVET_TIME_872MSEC, +} t_ab8500_codec_cr14_envet_time; + +/* CR15 - 7 */ +typedef enum { + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH, + AB8500_CODEC_CR15_PWMTOVIBL_PWM +} t_ab8500_codec_cr15_pwmtovibl; + +/* CR15 - 6 */ +typedef enum { + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH, + AB8500_CODEC_CR15_PWMTOVIBR_PWM +} t_ab8500_codec_cr15_pwmtovibr; + +/* CR15 - 5 */ +typedef enum { + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL, + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE +} t_ab8500_codec_cr15_pwmlctrl; + +/* CR15 - 4 */ +typedef enum { + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL, + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE +} t_ab8500_codec_cr15_pwmrctrl; + +/* CR15 - 3 */ +typedef enum { + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL, + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE +} t_ab8500_codec_cr15_pwmnlctrl; + +/* CR15 - 2 */ +typedef enum { + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL, + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE +} t_ab8500_codec_cr15_pwmplctrl; + +/* CR15 - 1 */ +typedef enum { + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL, + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE +} t_ab8500_codec_cr15_pwmnrctrl; + +/* CR15 - 0 */ +typedef enum { + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL, + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE +} t_ab8500_codec_cr15_pwmprctrl; + +/* CR16 - 7 */ +typedef enum { + AB8500_CODEC_CR16_PWMNLPOL_GNDVIB, + AB8500_CODEC_CR16_PWMNLPOL_VINVIB +} t_ab8500_codec_cr16_pwmnlpol; + +/* CR16 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr16_pwmnldutycycle; + +/* CR17 - 7 */ +typedef enum { + AB8500_CODEC_CR17_PWMPLPOL_GNDVIB, + AB8500_CODEC_CR17_PWMPLPOL_VINVIB +} t_ab8500_codec_cr17_pwmplpol; + +/* CR17 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr17_pwmpldutycycle; + +/* CR18 - 7 */ +typedef enum { + AB8500_CODEC_CR18_PWMNRPOL_GNDVIB, + AB8500_CODEC_CR18_PWMNRPOL_VINVIB +} t_ab8500_codec_cr18_pwmnrpol; + +/* CR18 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr18_pwmnrdutycycle; + +/* CR19 - 7 */ +typedef enum { + AB8500_CODEC_CR19_PWMPRPOL_GNDVIB, + AB8500_CODEC_CR19_PWMPRPOL_VINVIB +} t_ab8500_codec_cr19_pwmprpol; + +/* CR19 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr19_pwmprdutycycle; + +/* CR20 - 7 */ +typedef enum { + AB8500_CODEC_CR20_EN_SE_MIC1_DIFFERENTIAL, + AB8500_CODEC_CR20_EN_SE_MIC1_SINGLE +} t_ab8500_codec_cr20_en_se_mic1; + +/* CR20 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr20_mic1_gain; + +/* CR21 - 7 */ +typedef enum { + AB8500_CODEC_CR21_EN_SE_MIC2_DIFFERENTIAL, + AB8500_CODEC_CR21_EN_SE_MIC2_SINGLE +} t_ab8500_codec_cr21_en_se_mic2; + +/* CR21 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr21_mic2_gain; + +/* CR22 - 7:5 */ +typedef t_uint8 t_ab8500_codec_cr22_hsl_gain; + +/* CR22 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr22_linl_gain; + +/* CR23 - 7:5 */ +typedef t_uint8 t_ab8500_codec_cr23_hsr_gain; + +/* CR23 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr23_linr_gain; + +/* CR24 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr24_lintohsl_gain; + +/* CR25 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr25_lintohsr_gain; + +/* CR26 - 7 */ +typedef enum { + AB8500_CODEC_CR26_AD1NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD1NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad1nh; + +/* CR26 - 6 */ +typedef enum { + AB8500_CODEC_CR26_AD2NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD2NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad2nh; + +/* CR26 - 5 */ +typedef enum { + AB8500_CODEC_CR26_AD3NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD3NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad3nh; + +/* CR26 - 4 */ +typedef enum { + AB8500_CODEC_CR26_AD4NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD4NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad4nh; + +/* CR26 - 3 */ +typedef enum { + AB8500_CODEC_CR26_AD1_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad1_voice; + +/* CR26 - 2 */ +typedef enum { + AB8500_CODEC_CR26_AD2_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad2_voice; + +/* CR26 - 1 */ +typedef enum { + AB8500_CODEC_CR26_AD3_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad3_voice; + +/* CR26 - 0 */ +typedef enum { + AB8500_CODEC_CR26_AD4_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad4_voice; + +/* CR27 - 7 */ +typedef enum { + AB8500_CODEC_CR27_EN_MASTGEN_DISABLED, + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED +} t_ab8500_codec_cr27_en_mastgen; + +/* CR27 - 6:5 */ +typedef enum { + AB8500_CODEC_CR27_IF1_BITCLK_OSR_32, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_64, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_128, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_256 +} t_ab8500_codec_cr27_if1_bitclk_osr; + +/* CR27 - 4 */ +typedef enum { + AB8500_CODEC_CR27_ENFS_BITCLK1_DISABLED, + AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED +} t_ab8500_codec_cr27_enfs_bitclk1; + +/* CR27 - 2:1 */ +typedef enum { + AB8500_CODEC_CR27_IF0_BITCLK_OSR_32, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_64, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_128, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_256 +} t_ab8500_codec_cr27_if0_bitclk_osr; + +/* CR27 - 0 */ +typedef enum { + AB8500_CODEC_CR27_ENFS_BITCLK0_DISABLED, + AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED +} t_ab8500_codec_cr27_enfs_bitclk0; + +/* CR28 - 6 */ +typedef enum { + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE, + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE +} t_ab8500_codec_cr28_fsync0p; + +/* CR28 - 5 */ +typedef enum { + AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE, + AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE +} t_ab8500_codec_cr28_bitclk0p; + +/* CR28 - 4 */ +typedef enum { + AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED, + AB8500_CODEC_CR28_IF0DEL_DELAYED +} t_ab8500_codec_cr28_if0del; + +/* CR28 - 3:2 */ +typedef enum { + AB8500_CODEC_CR28_IF0FORMAT_DISABLED, + AB8500_CODEC_CR28_IF0FORMAT_TDM, + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED +} t_ab8500_codec_cr28_if0format; + +/* CR28 - 1:0 */ +typedef enum { + AB8500_CODEC_CR28_IF0WL_16BITS, + AB8500_CODEC_CR28_IF0WL_20BITS, + AB8500_CODEC_CR28_IF0WL_24BITS, + AB8500_CODEC_CR28_IF0WL_32BITS +} t_ab8500_codec_cr28_if0wl; + +/* CR29 - 7 */ +typedef enum { + AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT, + AB8500_CODEC_CR29_IF0DATOIF1AD_SENT +} t_ab8500_codec_cr29_if0datoif1ad; + +/* CR29 - 6 */ +typedef enum { + AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT, + AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT +} t_ab8500_codec_cr29_if0cktoif1ck; + +/* CR29 - 5 */ +typedef enum { + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT, + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT +} t_ab8500_codec_cr29_if1master; + +/* CR29 - 3 */ +typedef enum { + AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT, + AB8500_CODEC_CR29_IF1DATOIF0AD_SENT +} t_ab8500_codec_cr29_if1datoif0ad; + +/* CR29 - 2 */ +typedef enum { + AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT, + AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT +} t_ab8500_codec_cr29_if1cktoif0ck; + +/* CR29 - 1 */ +typedef enum { + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT, + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT +} t_ab8500_codec_cr29_if0master; + +/* CR29 - 0 */ +typedef enum { + AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE, + AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE +} t_ab8500_codec_cr29_if0bfifoen; + +/* CR30 - 6 */ +typedef enum { + AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE, + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE +} t_ab8500_codec_cr30_fsync1p; + +/* CR30 - 5 */ +typedef enum { + AB8500_CODEC_CR30_BITCLK1P_RISING_EDGE, + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE +} t_ab8500_codec_cr30_bitclk1p; + +/* CR30 - 4 */ +typedef enum { + AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED, + AB8500_CODEC_CR30_IF1DEL_DELAYED +} t_ab8500_codec_cr30_if1del; + +/* CR30 - 3:2 */ +typedef enum { + AB8500_CODEC_CR30_IF1FORMAT_DISABLED, + AB8500_CODEC_CR30_IF1FORMAT_TDM, + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED +} t_ab8500_codec_cr30_if1format; + +/* CR30 - 1:0 */ +typedef enum { + AB8500_CODEC_CR30_IF1WL_16BITS, + AB8500_CODEC_CR30_IF1WL_20BITS, + AB8500_CODEC_CR30_IF1WL_24BITS, + AB8500_CODEC_CR30_IF1WL_32BITS +} t_ab8500_codec_cr30_if1wl; + +/* CR31:46 - 7:4 or 3:0 */ +/* In ab8500_codec.h */ + +/* CR47:50 - 7/6/5/4/3/2/1/0 */ +typedef enum { + AB8500_CODEC_CR47_TO_CR50_HIZ_SL_LOW_IMPEDANCE, + AB8500_CODEC_CR47_TO_CR50_HIZ_SL_HIGH_IMPEDANCE, +} t_ab8500_codec_cr47_to_cr50_hiz_sl; + +/* CR51 - 7 */ +typedef enum { + AB8500_CODEC_CR51_DA12_VOICE_AUDIOFILTER, + AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr51_da12_voice; + +/* CR51 - 5 */ +typedef enum { + AB8500_CODEC_CR51_SLDAI1TOSLADO1_NOT_LOOPEDBACK, + AB8500_CODEC_CR51_SLDAI1TOSLADO1_LOOPEDBACK +} t_ab8500_codec_cr51_sldai1toslado1; + +/* CR51:56 - 4:0 */ +/* In ab8500_codec.h */ + +/* CR52 - 5 */ +typedef enum { + AB8500_CODEC_CR52_SLDAI2TOSLADO2_NOT_LOOPEDBACK, + AB8500_CODEC_CR52_SLDAI2TOSLADO2_LOOPEDBACK +} t_ab8500_codec_cr52_sldai2toslado2; + +/* CR53 - 7 */ +typedef enum { + AB8500_CODEC_CR53_DA34_VOICE_AUDIOFILTER, + AB8500_CODEC_CR53_DA34_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr53_da34_voice; + +/* CR53 - 5 */ +typedef enum { + AB8500_CODEC_CR53_SLDAI3TOSLADO3_NOT_LOOPEDBACK, + AB8500_CODEC_CR53_SLDAI3TOSLADO3_LOOPEDBACK +} t_ab8500_codec_cr53_sldai3toslado3; + +/* CR54 - 5 */ +typedef enum { + AB8500_CODEC_CR54_SLDAI4TOSLADO4_NOT_LOOPEDBACK, + AB8500_CODEC_CR54_SLDAI4TOSLADO4_LOOPEDBACK +} t_ab8500_codec_cr54_sldai4toslado4; + +/* CR55 - 7 */ +typedef enum { + AB8500_CODEC_CR55_DA56_VOICE_AUDIOFILTER, + AB8500_CODEC_CR55_DA56_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr55_da56_voice; + +/* CR55 - 6:5 */ +typedef enum { + AB8500_CODEC_CR55_SLDAI5TOSLADO5_NOT_LOOPEDBACK, + AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN1_LOOPEDBACK, + AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN3_LOOPEDBACK, + AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN5_LOOPEDBACK +} t_ab8500_codec_cr55_sldai5toslado5; + +/* CR56 - 6:5 */ +typedef enum { + AB8500_CODEC_CR56_SLDAI6TOSLADO7_NOT_LOOPEDBACK, + AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN2_LOOPEDBACK, + AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN4_LOOPEDBACK, + AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN6_LOOPEDBACK +} t_ab8500_codec_cr56_sldai6toslado7; + +/* CR57 - 6 */ +typedef enum { + AB8500_CODEC_CR57_BFIFULL_MSK_MASKED, + AB8500_CODEC_CR57_BFIFULL_MSK_ENABLED +} t_ab8500_codec_cr57_bfifull_msk; + +/* CR57 - 5 */ +typedef enum { + AB8500_CODEC_CR57_BFIEMPT_MSK_MASKED, + AB8500_CODEC_CR57_BFIEMPT_MSK_ENABLED +} t_ab8500_codec_cr57_bfiempt_msk; + +/* CR57 - 4 */ +typedef enum { + AB8500_CODEC_CR57_DACHAN_MSK_MASKED, + AB8500_CODEC_CR57_DACHAN_MSK_ENABLED +} t_ab8500_codec_cr57_dachan_msk; + +/* CR57 - 3 */ +typedef enum { + AB8500_CODEC_CR57_GAIN_MSK_MASKED, + AB8500_CODEC_CR57_GAIN_MSK_ENABLED +} t_ab8500_codec_cr57_gain_msk; + +/* CR57 - 2 */ +typedef enum { + AB8500_CODEC_CR57_DSPAD_MSK_MASKED, + AB8500_CODEC_CR57_DSPAD_MSK_ENABLED +} t_ab8500_codec_cr57_dspad_msk; + +/* CR57 - 1 */ +typedef enum { + AB8500_CODEC_CR57_DSPDA_MSK_MASKED, + AB8500_CODEC_CR57_DSPDA_MSK_ENABLED +} t_ab8500_codec_cr57_dspda_msk; + +/* CR57 - 0 */ +typedef enum { + AB8500_CODEC_CR57_STFIR_MSK_MASKED, + AB8500_CODEC_CR57_STFIR_MSK_ENABLED +} t_ab8500_codec_cr57_stfir_msk; + +/* CR58 - Read Only */ +/* CR58 - 6 */ +typedef enum { + AB8500_CODEC_CR58_BFIFULL_EV_NOT_FULL, + AB8500_CODEC_CR58_BFIFULL_EV_FULL +} t_ab8500_codec_cr58_bfifull_ev; + +/* CR58 - 5 */ +typedef enum { + AB8500_CODEC_CR58_BFIEMPT_EV_NOT_EMPTY, + AB8500_CODEC_CR58_BFIEMPT_EV_EMPTY +} t_ab8500_codec_cr58_bfiempt_ev; + +/* CR58 - 4 */ +typedef enum { + AB8500_CODEC_CR58_DACHAN_EV_NO_SATURATION, + AB8500_CODEC_CR58_DACHAN_EV_SATURATION +} t_ab8500_codec_cr58_dachan_ev; + +/* CR58 - 3 */ +typedef enum { + AB8500_CODEC_CR58_GAIN_EV_NO_SATURATION, + AB8500_CODEC_CR58_GAIN_EV_SATURATION +} t_ab8500_codec_cr58_gain_ev; + +/* CR58 - 2 */ +typedef enum { + AB8500_CODEC_CR58_DSPAD_EV_NO_SATURATION, + AB8500_CODEC_CR58_DSPAD_EV_SATURATION +} t_ab8500_codec_cr58_dspad_ev; + +/* CR58 - 1 */ +typedef enum { + AB8500_CODEC_CR58_DSPDA_EV_NO_SATURATION, + AB8500_CODEC_CR58_DSPDA_EV_SATURATION +} t_ab8500_codec_cr58_dspda_ev; + +/* CR58 - 0 */ +typedef enum { + AB8500_CODEC_CR58_STFIR_EV_NO_SATURATION, + AB8500_CODEC_CR58_STFIR_EV_SATURATION +} t_ab8500_codec_cr58_stfir_ev; + +/* CR59 - 7 */ +typedef enum { + AB8500_CODEC_CR59_VSSREADY_MSK_MASKED, + AB8500_CODEC_CR59_VSSREADY_MSK_ENABLED +} t_ab8500_codec_cr59_vssready_msk; + +/* CR59 - 6 */ +typedef enum { + AB8500_CODEC_CR59_SHRTVIBL_MSK_MASKED, + AB8500_CODEC_CR59_SHRTVIBL_MSK_ENABLED +} t_ab8500_codec_cr59_shrtvibl_msk; + +/* CR59 - 5 */ +typedef enum { + AB8500_CODEC_CR59_SHRTVIBR_MSK_MASKED, + AB8500_CODEC_CR59_SHRTVIBR_MSK_ENABLED +} t_ab8500_codec_cr59_shrtvibr_msk; + +/* CR59 - 4 */ +typedef enum { + AB8500_CODEC_CR59_SHRTHFL_MSK_MASKED, + AB8500_CODEC_CR59_SHRTHFL_MSK_ENABLED +} t_ab8500_codec_cr59_shrthfl_msk; + +/* CR59 - 3 */ +typedef enum { + AB8500_CODEC_CR59_SHRTHFR_MSK_MASKED, + AB8500_CODEC_CR59_SHRTHFR_MSK_ENABLED +} t_ab8500_codec_cr59_shrthfr_msk; + +/* CR59 - 2 */ +typedef enum { + AB8500_CODEC_CR59_SHRTHSL_MSK_MASKED, + AB8500_CODEC_CR59_SHRTHSL_MSK_ENABLED +} t_ab8500_codec_cr59_shrthsl_msk; + +/* CR59 - 1 */ +typedef enum { + AB8500_CODEC_CR59_SHRTHSR_MSK_MASKED, + AB8500_CODEC_CR59_SHRTHSR_MSK_ENABLED +} t_ab8500_codec_cr59_shrthsr_msk; + +/* CR59 - 0 */ +typedef enum { + AB8500_CODEC_CR59_SHRTEAR_MSK_MASKED, + AB8500_CODEC_CR59_SHRTEAR_MSK_ENABLED +} t_ab8500_codec_cr59_shrtear_msk; + +/* CR60 - Read Only */ +/* CR60 - 7 */ +typedef enum { + AB8500_CODEC_CR60_VSSREADY_EV_NOT_READY, + AB8500_CODEC_CR60_VSSREADY_EV_READY +} t_ab8500_codec_cr60_vssready_ev; + +/* CR60 - 6 */ +typedef enum { + AB8500_CODEC_CR60_SHRTVIBL_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTVIBL_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrtvibl_ev; + +/* CR60 - 5 */ +typedef enum { + AB8500_CODEC_CR60_SHRTVIBR_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTVIBR_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrtvibr_ev; + +/* CR60 - 4 */ +typedef enum { + AB8500_CODEC_CR60_SHRTHFL_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTHFL_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrthfl_ev; + +/* CR60 - 3 */ +typedef enum { + AB8500_CODEC_CR60_SHRTHFR_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTHFR_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrthfr_ev; + +/* CR60 - 2 */ +typedef enum { + AB8500_CODEC_CR60_SHRTHSL_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTHSL_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrthsl_ev; + +/* CR60 - 1 */ +typedef enum { + AB8500_CODEC_CR60_SHRTHSR_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTHSR_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrthsr_ev; + +/* CR60 - 0 */ +typedef enum { + AB8500_CODEC_CR60_SHRTEAR_EV_NO_SHORTCIRCUIT, + AB8500_CODEC_CR60_SHRTEAR_EV_SHORTCIRCUIT +} t_ab8500_codec_cr60_shrtear_ev; + +/* CR61 - 6:2 - Read Only */ +typedef enum { + AB8500_CODEC_CR61_REVISION_1_0, + AB8500_CODEC_CR61_REVISION_TBD +} t_ab8500_codec_cr61_revision; + +/* CR61 - 1:0 */ +typedef enum { + AB8500_CODEC_CR61_FADE_SPEED_1MS, + AB8500_CODEC_CR61_FADE_SPEED_4MS, + AB8500_CODEC_CR61_FADE_SPEED_8MS, + AB8500_CODEC_CR61_FADE_SPEED_16MS +} t_ab8500_codec_cr61_fade_speed; + +/* CR62 - Read Only */ +/* CR62 - 5 */ +typedef enum { + AB8500_CODEC_CR62_DMIC1SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC1SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic1sinc3; + +/* CR62 - 4 */ +typedef enum { + AB8500_CODEC_CR62_DMIC2SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC2SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic2sinc3; + +/* CR62 - 3 */ +typedef enum { + AB8500_CODEC_CR62_DMIC3SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC3SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic3sinc3; + +/* CR62 - 2 */ +typedef enum { + AB8500_CODEC_CR62_DMIC4SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC4SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic4sinc3; + +/* CR62 - 1 */ +typedef enum { + AB8500_CODEC_CR62_DMIC5SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC5SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic5sinc3; + +/* CR62 - 0 */ +typedef enum { + AB8500_CODEC_CR62_DMIC6SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC6SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic6sinc3; + +/* CR63 - 7 */ +typedef enum { + AB8500_CODEC_CR63_DATOHSLEN_DISABLED, + AB8500_CODEC_CR63_DATOHSLEN_ENABLED +} t_ab8500_codec_cr63_datohslen; + +/* CR63 - 6 */ +typedef enum { + AB8500_CODEC_CR63_DATOHSREN_DISABLED, + AB8500_CODEC_CR63_DATOHSREN_ENABLED +} t_ab8500_codec_cr63_datohsren; + +/* CR63 - 5 */ +typedef enum { + AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED, + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED +} t_ab8500_codec_cr63_ad1sel; + +/* CR63 - 4 */ +typedef enum { + AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED, + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED +} t_ab8500_codec_cr63_ad2sel; + +/* CR63 - 3 */ +typedef enum { + AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED, + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED +} t_ab8500_codec_cr63_ad3sel; + +/* CR63 - 2 */ +typedef enum { + AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED, + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED +} t_ab8500_codec_cr63_ad5sel; + +/* CR63 - 1 */ +typedef enum { + AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED, + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED +} t_ab8500_codec_cr63_ad6sel; + +/* CR63 - 0 */ +typedef enum { + AB8500_CODEC_CR63_ANCSEL_NOT_MIXED_IN_EAR, + AB8500_CODEC_CR63_ANCSEL_MIXED_IN_EAR +} t_ab8500_codec_cr63_ancsel; + +/* CR64 - 7 */ +typedef enum { + AB8500_CODEC_CR64_DATOHFREN_NOT_MIXED_TO_HFR, + AB8500_CODEC_CR64_DATOHFREN_MIXED_TO_HFR +} t_ab8500_codec_cr64_datohfren; + +/* CR64 - 6 */ +typedef enum { + AB8500_CODEC_CR64_DATOHFLEN_NOT_MIXED_TO_HFL, + AB8500_CODEC_CR64_DATOHFLEN_MIXED_TO_HFL +} t_ab8500_codec_cr64_datohflen; + +/* CR64 - 5 */ +typedef enum { + AB8500_CODEC_CR64_HFRSEL_DA4_MIXED_TO_HFR, + AB8500_CODEC_CR64_HFRSEL_ANC_MIXED_TO_HFR +} t_ab8500_codec_cr64_hfrsel; + +/* CR64 - 4 */ +typedef enum { + AB8500_CODEC_CR64_HFLSEL_DA3_MIXED_TO_HFL, + AB8500_CODEC_CR64_HFLSEL_ANC_MIXED_TO_HFL +} t_ab8500_codec_cr64_hflsel; + +/* CR64 - 3:2 */ +typedef enum { + AB8500_CODEC_CR64_STFIR1SEL_AD_OUT1_SELECTED, + AB8500_CODEC_CR64_STFIR1SEL_AD_OUT3_SELECTED, + AB8500_CODEC_CR64_STFIR1SEL_DA_IN1_SELECTED +} t_ab8500_codec_cr64_stfir1sel; + +/* CR64 - 1:0 */ +typedef enum { + AB8500_CODEC_CR64_STFIR2SEL_AD_OUT2_SELECTED, + AB8500_CODEC_CR64_STFIR2SEL_AD_OUT4_SELECTED, + AB8500_CODEC_CR64_STFIR2SEL_DA_IN2_SELECTED +} t_ab8500_codec_cr64_stfir2sel; + +/* CR65 - 6 */ +typedef enum { + AB8500_CODEC_CR65_FADEDIS_AD1_ENABLED, + AB8500_CODEC_CR65_FADEDIS_AD1_DISABLED +} t_ab8500_codec_cr65_fadedis_ad1; + +/* CR65 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr65_ad1gain; + +/* CR66 - 6 */ +typedef enum { + AB8500_CODEC_CR66_FADEDIS_AD2_ENABLED, + AB8500_CODEC_CR66_FADEDIS_AD2_DISABLED +} t_ab8500_codec_cr66_fadedis_ad2; + +/* CR66 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr66_ad2gain; + +/* CR67 - 6 */ +typedef enum { + AB8500_CODEC_CR67_FADEDIS_AD3_ENABLED, + AB8500_CODEC_CR67_FADEDIS_AD3_DISABLED +} t_ab8500_codec_cr67_fadedis_ad3; + +/* CR67 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr67_ad3gain; + +/* CR68 - 6 */ +typedef enum { + AB8500_CODEC_CR68_FADEDIS_AD4_ENABLED, + AB8500_CODEC_CR68_FADEDIS_AD4_DISABLED +} t_ab8500_codec_cr68_fadedis_ad4; + +/* CR68 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr68_ad4gain; + +/* CR69 - 6 */ +typedef enum { + AB8500_CODEC_CR69_FADEDIS_AD5_ENABLED, + AB8500_CODEC_CR69_FADEDIS_AD5_DISABLED +} t_ab8500_codec_cr69_fadedis_ad5; + +/* CR69 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr69_ad5gain; + +/* CR70 - 6 */ +typedef enum { + AB8500_CODEC_CR70_FADEDIS_AD6_ENABLED, + AB8500_CODEC_CR70_FADEDIS_AD6_DISABLED +} t_ab8500_codec_cr70_fadedis_ad6; + +/* CR70 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr70_ad6gain; + +/* CR71 - 6 */ +typedef enum { + AB8500_CODEC_CR71_FADEDIS_DA1_ENABLED, + AB8500_CODEC_CR71_FADEDIS_DA1_DISABLED +} t_ab8500_codec_cr71_fadedis_da1; + +/* CR71 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr71_da1gain; + +/* CR72 - 6 */ +typedef enum { + AB8500_CODEC_CR72_FADEDIS_DA2_ENABLED, + AB8500_CODEC_CR72_FADEDIS_DA2_DISABLED +} t_ab8500_codec_cr72_fadedis_da2; + +/* CR72 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr72_da2gain; + +/* CR73 - 6 */ +typedef enum { + AB8500_CODEC_CR73_FADEDIS_DA3_ENABLED, + AB8500_CODEC_CR73_FADEDIS_DA3_DISABLED +} t_ab8500_codec_cr73_fadedis_da3; + +/* CR73 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr73_da3gain; + +/* CR74 - 6 */ +typedef enum { + AB8500_CODEC_CR74_FADEDIS_DA4_ENABLED, + AB8500_CODEC_CR74_FADEDIS_DA4_DISABLED +} t_ab8500_codec_cr74_fadedis_da4; + +/* CR74 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr74_da4gain; + +/* CR75 - 6 */ +typedef enum { + AB8500_CODEC_CR75_FADEDIS_DA5_ENABLED, + AB8500_CODEC_CR75_FADEDIS_DA5_DISABLED +} t_ab8500_codec_cr75_fadedis_da5; + +/* CR75 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr75_da5gain; + +/* CR76 - 6 */ +typedef enum { + AB8500_CODEC_CR76_FADEDIS_DA6_ENABLED, + AB8500_CODEC_CR76_FADEDIS_DA6_DISABLED +} t_ab8500_codec_cr76_fadedis_da6; + +/* CR76 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr76_da6gain; + +/* CR77 - 6 */ +typedef enum { + AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_ENABLED, + AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_DISABLED +} t_ab8500_codec_cr77_fadedis_ad1l; + +/* CR77 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr77_ad1lbgain_to_hfl; + +/* CR78 - 6 */ +typedef enum { + AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_ENABLED, + AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_DISABLED +} t_ab8500_codec_cr78_fadedis_ad2l; + +/* CR78 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr78_ad2lbgain_to_hfr; + +/* CR79 - 7 */ +typedef enum { + AB8500_CODEC_CR79_HSSINC1_SINC3_CHOOSEN, + AB8500_CODEC_CR79_HSSINC1_SINC1_CHOOSEN +} t_ab8500_codec_cr79_hssinc1; + +/* CR79 - 4 */ +typedef enum { + AB8500_CODEC_CR79_FADEDIS_HSL_ENABLED, + AB8500_CODEC_CR79_FADEDIS_HSL_DISABLED +} t_ab8500_codec_cr79_fadedis_hsl; + +/* CR79 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr79_hsldgain; + +/* CR80 - 4 */ +typedef enum { + AB8500_CODEC_CR80_FADEDIS_HSR_ENABLED, + AB8500_CODEC_CR80_FADEDIS_HSR_DISABLED +} t_ab8500_codec_cr80_fadedis_hsr; + +/* CR80 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr80_hsrdgain; + +/* CR81 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr81_stfir1gain; + +/* CR82 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr82_stfir2gain; + +/* CR83 - 2 */ +typedef enum { + AB8500_CODEC_CR83_ENANC_DISABLED, + AB8500_CODEC_CR83_ENANC_ENABLED +} t_ab8500_codec_cr83_enanc; + +/* CR83 - 1 */ +typedef enum { + AB8500_CODEC_CR83_ANCIIRINIT_NOT_STARTED, + AB8500_CODEC_CR83_ANCIIRINIT_STARTED +} t_ab8500_codec_cr83_anciirinit; + +/* CR83 - 0 */ +typedef enum { + AB8500_CODEC_CR83_ANCFIRUPDATE_RESETTED, + AB8500_CODEC_CR83_ANCFIRUPDATE_NOT_RESETTED +} t_ab8500_codec_cr83_ancfirupdate; + +/* CR84 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr84_ancinshift; + +/* CR85 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr85_ancfiroutshift; + +/* CR86 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr86_ancshiftout; + +/* CR87 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr87_ancfircoeff_msb; + +/* CR88 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr88_ancfircoeff_lsb; + +/* CR89 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr89_anciircoeff_msb; + +/* CR90 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr90_anciircoeff_lsb; + +/* CR91 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr91_ancwarpdel_msb; + +/* CR92 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr92_ancwarpdel_lsb; + +/* CR93 - Read Only */ +/* CR93 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr93_ancfirpeak_msb; + +/* CR94 - Read Only */ +/* CR94 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr94_ancfirpeak_lsb; + +/* CR95 - Read Only */ +/* CR95 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr95_anciirpeak_msb; + +/* CR96 - Read Only */ +/* CR96 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr96_anciirpeak_lsb; + +/* CR97 - 7 */ +typedef enum { + AB8500_CODEC_CR97_STFIR_SET_LAST_NOT_APPLIED, + AB8500_CODEC_CR97_STFIR_SET_LAST_APPLIED +} t_ab8500_codec_cr97_stfir_set; + +/* CR97 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr97_stfir_addr; + +/* CR98 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr98_stfir_coeff_msb; + +/* CR99 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr99_stfir_coeff_lsb; + +/* CR100 - 2 */ +typedef enum { + AB8500_CODEC_CR100_ENSTFIRS_DISABLED, + AB8500_CODEC_CR100_ENSTFIRS_ENABLED +} t_ab8500_codec_cr100_enstfirs; + +/* CR100 - 1 */ +typedef enum { + AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF0_DATA_RATE, + AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF1_DATA_RATE +} t_ab8500_codec_cr100_stfirstoif1; + +/* CR100 - 0 */ +typedef enum { + AB8500_CODEC_CR100_STFIR_BUSY_READY, + AB8500_CODEC_CR100_STFIR_BUSY_NOT_READY +} t_ab8500_codec_cr100_stfir_busy; + +/* CR101 - 7 */ +typedef enum { + AB8500_CODEC_CR101_PARLHF_INDEPENDENT, + AB8500_CODEC_CR101_PARLHF_BRIDGED +} t_ab8500_codec_cr101_parlhf; + +/* CR101 - 6 */ +typedef enum { + AB8500_CODEC_CR101_PARLVIB_INDEPENDENT, + AB8500_CODEC_CR101_PARLVIB_BRIDGED +} t_ab8500_codec_cr101_parlvib; + +/* CR101 - 3 */ +typedef enum { + AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_DISABLED, + AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_ENABLED +} t_ab8500_codec_cr101_classd_viblswapen; + +/* CR101 - 2 */ +typedef enum { + AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_DISABLED, + AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_ENABLED +} t_ab8500_codec_cr101_classd_vibrswapen; + +/* CR101 - 1 */ +typedef enum { + AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_DISABLED, + AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_ENABLED +} t_ab8500_codec_cr101_classd_hflswapen; + +/* CR101 - 0 */ +typedef enum { + AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_DISABLED, + AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_ENABLED +} t_ab8500_codec_cr101_classd_hfrswapen; + +/* CR102 - 7:4 */ +typedef enum { + AB8500_CODEC_CR102_CLASSD_FIRBYP_ALL_ENABLED = 0, + AB8500_CODEC_CR102_CLASSD_FIRBYP_HFL_BYPASSED = 1, + AB8500_CODEC_CR102_CLASSD_FIRBYP_HFR_BYPASSED = 2, + AB8500_CODEC_CR102_CLASSD_FIRBYP_VIBL_BYPASSED = 4, + AB8500_CODEC_CR102_CLASSD_FIRBYP_VIBR_BYPASSED = 8 +} t_ab8500_codec_cr102_classd_firbyp; + +/* CR102 - 3:0 */ +typedef enum { + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_DISABLED = 0, + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_HFL_HIGHVOL = 1, + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_HFR_HIGHVOL = 2, + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_VIBL_HIGHVOL = 4, + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_VIBR_HIGHVOL = 8 +} t_ab8500_codec_cr102_classd_highvolen; + +/* CR103 - 7:4 */ +typedef t_uint8 t_ab8500_codec_cr103_classd_ditherhpgain; + +/* CR103 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr103_classd_ditherwgain; + +/* CR104 - 5:0 */ +/* In ab8500_codec.h */ + +/* CR105 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR106 - 6:4 */ +/* In ab8500_codec.h */ + +/* CR106 - 2 */ +/* In ab8500_codec.h */ + +/* CR106 - 1 */ +/* In ab8500_codec.h */ + +/* CR106 - 0 */ +/* In ab8500_codec.h */ + +/* CR107 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR108 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR109 - Read Only */ +/* CR109 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr109_bfifosamples; + +typedef enum { + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_ZEROS, + AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE = 15, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED +} t_ab8500_codec_cr31_to_cr46_ad_data_allocation; + +typedef enum { + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT00, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT01, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT02, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT03, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT04, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT05, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT06, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT07, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT10, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT11, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT14, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT15, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT16, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT17, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT18, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT19, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT20, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT21, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT22, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT23, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT24, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT25, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT26, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT27, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT28, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT29, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT30, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT31, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED +} t_ab8500_codec_cr51_to_cr56_sltoda; + +/* CR104 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr104_bfifoint; + +/* CR105 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr105_bfifotx; + +/* CR106 - 6:4 */ +typedef enum { + AB8500_CODEC_CR106_BFIFOFSEXT_NO_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_1SLOT_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_2SLOT_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_3SLOT_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_4SLOT_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_5SLOT_EXTRA_CLK, + AB8500_CODEC_CR106_BFIFOFSEXT_6SLOT_EXTRA_CLK +} t_ab8500_codec_cr106_bfifofsext; + +/* CR106 - 2 */ +typedef enum { + AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_UNMASKED, + AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_MASKED +} t_ab8500_codec_cr106_bfifomsk; + +/* CR106 - 1 */ +typedef enum { + AB8500_CODEC_CR106_BFIFOMSTR_SLAVE_MODE, + AB8500_CODEC_CR106_BFIFOMSTR_MASTER_MODE +} t_ab8500_codec_cr106_bfifomstr; + +/* CR106 - 0 */ +typedef enum { + AB8500_CODEC_CR106_BFIFOSTRT_STOPPED, + AB8500_CODEC_CR106_BFIFOSTRT_RUNNING +} t_ab8500_codec_cr106_bfifostrt; + +/* CR107 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr107_bfifosampnr; + +/* CR108 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr108_bfifowakeup; + +/*configuration structure for AB8500 Codec*/ +typedef struct { + /* CR0 */ + t_ab8500_codec_cr0_powerup cr0_powerup; + t_ab8500_codec_cr0_enaana cr0_enaana; + + /* CR1 */ + t_ab8500_codec_cr1_swreset cr1_swreset; + + /* CR2 */ + t_ab8500_codec_cr2_enad1 cr2_enad1; + t_ab8500_codec_cr2_enad2 cr2_enad2; + t_ab8500_codec_cr2_enad3 cr2_enad3; + t_ab8500_codec_cr2_enad4 cr2_enad4; + t_ab8500_codec_cr2_enad5 cr2_enad5; + t_ab8500_codec_cr2_enad6 cr2_enad6; + + /* CR3 */ + t_ab8500_codec_cr3_enda1 cr3_enda1; + t_ab8500_codec_cr3_enda2 cr3_enda2; + t_ab8500_codec_cr3_enda3 cr3_enda3; + t_ab8500_codec_cr3_enda4 cr3_enda4; + t_ab8500_codec_cr3_enda5 cr3_enda5; + t_ab8500_codec_cr3_enda6 cr3_enda6; + + /* CR4 */ + t_ab8500_codec_cr4_lowpowhs cr4_lowpowhs; + t_ab8500_codec_cr4_lowpowdachs cr4_lowpowdachs; + t_ab8500_codec_cr4_lowpowear cr4_lowpowear; + t_ab8500_codec_cr4_ear_sel_cm cr4_ear_sel_cm; + t_ab8500_codec_cr4_hs_hp_dis cr4_hs_hp_dis; + t_ab8500_codec_cr4_ear_hp_dis cr4_ear_hp_dis; + + /* CR5 */ + t_ab8500_codec_cr5_enmic1 cr5_enmic1; + t_ab8500_codec_cr5_enmic2 cr5_enmic2; + t_ab8500_codec_cr5_enlinl cr5_enlinl; + t_ab8500_codec_cr5_enlinr cr5_enlinr; + t_ab8500_codec_cr5_mutmic1 cr5_mutmic1; + t_ab8500_codec_cr5_mutmic2 cr5_mutmic2; + t_ab8500_codec_cr5_mutlinl cr5_mutlinl; + t_ab8500_codec_cr5_mutlinr cr5_mutlinr; + + /* CR6 */ + t_ab8500_codec_cr6_endmic1 cr6_endmic1; + t_ab8500_codec_cr6_endmic2 cr6_endmic2; + t_ab8500_codec_cr6_endmic3 cr6_endmic3; + t_ab8500_codec_cr6_endmic4 cr6_endmic4; + t_ab8500_codec_cr6_endmic5 cr6_endmic5; + t_ab8500_codec_cr6_endmic6 cr6_endmic6; + + /* CR7 */ + t_ab8500_codec_cr7_mic1sel cr7_mic1sel; + t_ab8500_codec_cr7_linrsel cr7_linrsel; + t_ab8500_codec_cr7_endrvhsl cr7_endrvhsl; + t_ab8500_codec_cr7_endrvhsr cr7_endrvhsr; + t_ab8500_codec_cr7_enadcmic cr7_enadcmic; + t_ab8500_codec_cr7_enadclinl cr7_enadclinl; + t_ab8500_codec_cr7_enadclinr cr7_enadclinr; + + /* CR8 */ + t_ab8500_codec_cr8_cp_dis_pldwn cr8_cp_dis_pldwn; + t_ab8500_codec_cr8_enear cr8_enear; + t_ab8500_codec_cr8_enhsl cr8_enhsl; + t_ab8500_codec_cr8_enhsr cr8_enhsr; + t_ab8500_codec_cr8_enhfl cr8_enhfl; + t_ab8500_codec_cr8_enhfr cr8_enhfr; + t_ab8500_codec_cr8_envibl cr8_envibl; + t_ab8500_codec_cr8_envibr cr8_envibr; + + /* CR9 */ + t_ab8500_codec_cr9_endacear cr9_endacear; + t_ab8500_codec_cr9_endachsl cr9_endachsl; + t_ab8500_codec_cr9_endachsr cr9_endachsr; + t_ab8500_codec_cr9_endachfl cr9_endachfl; + t_ab8500_codec_cr9_endachfr cr9_endachfr; + t_ab8500_codec_cr9_endacvibl cr9_endacvibl; + t_ab8500_codec_cr9_endacvibr cr9_endacvibr; + + /* CR10 */ + t_ab8500_codec_cr10_muteear cr10_muteear; + t_ab8500_codec_cr10_mutehsl cr10_mutehsl; + t_ab8500_codec_cr10_mutehsr cr10_mutehsr; + t_ab8500_codec_cr10_mutehfl cr10_mutehfl; + t_ab8500_codec_cr10_mutehfr cr10_mutehfr; + t_ab8500_codec_cr10_mutevibl cr10_mutevibl; + t_ab8500_codec_cr10_mutevibr cr10_mutevibr; + + /* CR11 */ + t_ab8500_codec_cr11_earshortpwd cr11_earshortpwd; + t_ab8500_codec_cr11_earshortdis cr11_earshortdis; + t_ab8500_codec_cr11_hslshortdis cr11_hslshortdis; + t_ab8500_codec_cr11_hsrshortdis cr11_hsrshortdis; + t_ab8500_codec_cr11_hflshortdis cr11_hflshortdis; + t_ab8500_codec_cr11_hfrshortdis cr11_hfrshortdis; + t_ab8500_codec_cr11_viblshortdis cr11_viblshortdis; + t_ab8500_codec_cr11_vibrshortdis cr11_vibrshortdis; + + /* CR12 */ + t_ab8500_codec_cr12_encphs cr12_encphs; + t_ab8500_codec_cr12_hsautotime cr12_hsautotime; + t_ab8500_codec_cr12_hsautoensel cr12_hsautoensel; + t_ab8500_codec_cr12_hsautoen cr12_hsautoen; + + /* CR13 */ + t_ab8500_codec_cr13_envdet_hthresh cr13_envdet_hthresh; + t_ab8500_codec_cr13_envdet_lthresh cr13_envdet_lthresh; + + /* CR14 */ + t_ab8500_codec_cr14_smpslven cr14_smpslven; + t_ab8500_codec_cr14_envdetsmpsen cr14_envdetsmpsen; + t_ab8500_codec_cr14_cplven cr14_cplven; + t_ab8500_codec_cr14_envdetcpen cr14_envdetcpen; + t_ab8500_codec_cr14_envet_time cr14_envet_time; + + /* CR15 */ + t_ab8500_codec_cr15_pwmtovibl cr15_pwmtovibl; + t_ab8500_codec_cr15_pwmtovibr cr15_pwmtovibr; + t_ab8500_codec_cr15_pwmlctrl cr15_pwmlctrl; + t_ab8500_codec_cr15_pwmrctrl cr15_pwmrctrl; + t_ab8500_codec_cr15_pwmnlctrl cr15_pwmnlctrl; + t_ab8500_codec_cr15_pwmplctrl cr15_pwmplctrl; + t_ab8500_codec_cr15_pwmnrctrl cr15_pwmnrctrl; + t_ab8500_codec_cr15_pwmprctrl cr15_pwmprctrl; + + /* CR16 */ + t_ab8500_codec_cr16_pwmnlpol cr16_pwmnlpol; + t_ab8500_codec_cr16_pwmnldutycycle cr16_pwmnldutycycle; + + /* CR17 */ + t_ab8500_codec_cr17_pwmplpol cr17_pwmplpol; + t_ab8500_codec_cr17_pwmpldutycycle cr17_pwmpldutycycle; + + /* CR18 */ + t_ab8500_codec_cr18_pwmnrpol cr18_pwmnrpol; + t_ab8500_codec_cr18_pwmnrdutycycle cr18_pwmnrdutycycle; + + /* CR19 */ + t_ab8500_codec_cr19_pwmprpol cr19_pwmprpol; + t_ab8500_codec_cr19_pwmprdutycycle cr19_pwmprdutycycle; + + /* CR20 */ + t_ab8500_codec_cr20_en_se_mic1 cr20_en_se_mic1; + t_ab8500_codec_cr20_mic1_gain cr20_mic1_gain; + + /* CR21 */ + t_ab8500_codec_cr21_en_se_mic2 cr21_en_se_mic2; + t_ab8500_codec_cr21_mic2_gain cr21_mic2_gain; + + /* CR22 */ + t_ab8500_codec_cr22_hsl_gain cr22_hsl_gain; + t_ab8500_codec_cr22_linl_gain cr22_linl_gain; + + /* CR23 */ + t_ab8500_codec_cr23_hsr_gain cr23_hsr_gain; + t_ab8500_codec_cr23_linr_gain cr23_linr_gain; + + /* CR24 */ + t_ab8500_codec_cr24_lintohsl_gain cr24_lintohsl_gain; + + /* CR25 */ + t_ab8500_codec_cr25_lintohsr_gain cr25_lintohsr_gain; + + /* CR26 */ + t_ab8500_codec_cr26_ad1nh cr26_ad1nh; + t_ab8500_codec_cr26_ad2nh cr26_ad2nh; + t_ab8500_codec_cr26_ad3nh cr26_ad3nh; + t_ab8500_codec_cr26_ad4nh cr26_ad4nh; + t_ab8500_codec_cr26_ad1_voice cr26_ad1_voice; + t_ab8500_codec_cr26_ad2_voice cr26_ad2_voice; + t_ab8500_codec_cr26_ad3_voice cr26_ad3_voice; + t_ab8500_codec_cr26_ad4_voice cr26_ad4_voice; + + /* CR27 */ + t_ab8500_codec_cr27_en_mastgen cr27_en_mastgen; + t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr; + t_ab8500_codec_cr27_enfs_bitclk1 cr27_enfs_bitclk1; + t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr; + t_ab8500_codec_cr27_enfs_bitclk0 cr27_enfs_bitclk0; + + /* CR28 */ + t_ab8500_codec_cr28_fsync0p cr28_fsync0p; + t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p; + t_ab8500_codec_cr28_if0del cr28_if0del; + t_ab8500_codec_cr28_if0format cr28_if0format; + t_ab8500_codec_cr28_if0wl cr28_if0wl; + + /* CR29 */ + t_ab8500_codec_cr29_if0datoif1ad cr29_if0datoif1ad; + t_ab8500_codec_cr29_if0cktoif1ck cr29_if0cktoif1ck; + t_ab8500_codec_cr29_if1master cr29_if1master; + t_ab8500_codec_cr29_if1datoif0ad cr29_if1datoif0ad; + t_ab8500_codec_cr29_if1cktoif0ck cr29_if1cktoif0ck; + t_ab8500_codec_cr29_if0master cr29_if0master; + t_ab8500_codec_cr29_if0bfifoen cr29_if0bfifoen; + + /* CR30 */ + t_ab8500_codec_cr30_fsync1p cr30_fsync1p; + t_ab8500_codec_cr30_bitclk1p cr30_bitclk1p; + t_ab8500_codec_cr30_if1del cr30_if1del; + t_ab8500_codec_cr30_if1format cr30_if1format; + t_ab8500_codec_cr30_if1wl cr30_if1wl; + + /* CR31 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot1; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot0; + + /* CR32 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot3; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot2; + + /* CR33 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot5; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot4; + + /* CR34 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot7; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot6; + + /* CR35 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot9; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot8; + + /* CR36 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot11; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot10; + + /* CR37 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot13; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot12; + + /* CR38 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot15; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot14; + + /* CR39 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot17; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot16; + + /* CR40 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot19; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot18; + + /* CR41 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot21; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot20; + + /* CR42 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot23; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot22; + + /* CR43 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot25; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot24; + + /* CR44 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot27; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot26; + + /* CR45 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot29; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot28; + + /* CR46 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot31; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot30; + + /* CR47 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl7; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl6; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl5; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl4; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl3; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl2; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl1; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl0; + + /* CR48 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl15; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl14; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl13; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl12; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl11; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl10; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl9; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl8; + + /* CR49 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl23; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl22; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl21; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl20; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl19; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl18; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl17; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl16; + + /* CR50 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl31; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl30; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl29; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl28; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl27; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl26; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl25; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl24; + + /* CR51 */ + t_ab8500_codec_cr51_da12_voice cr51_da12_voice; + t_ab8500_codec_cr51_sldai1toslado1 cr51_sldai1toslado1; + t_ab8500_codec_cr51_to_cr56_sltoda cr51_sltoda1; + + /* CR52 */ + t_ab8500_codec_cr52_sldai2toslado2 cr52_sldai2toslado2; + t_ab8500_codec_cr51_to_cr56_sltoda cr52_sltoda2; + + /* CR53 */ + t_ab8500_codec_cr53_da34_voice cr53_da34_voice; + t_ab8500_codec_cr53_sldai3toslado3 cr53_sldai3toslado3; + t_ab8500_codec_cr51_to_cr56_sltoda cr53_sltoda3; + + /* CR54 */ + t_ab8500_codec_cr54_sldai4toslado4 cr54_sldai4toslado4; + t_ab8500_codec_cr51_to_cr56_sltoda cr54_sltoda4; + + /* CR55 */ + t_ab8500_codec_cr55_da56_voice cr55_da56_voice; + t_ab8500_codec_cr55_sldai5toslado5 cr55_sldai5toslado5; + t_ab8500_codec_cr51_to_cr56_sltoda cr55_sltoda5; + + /* CR56 */ + t_ab8500_codec_cr56_sldai6toslado7 cr56_sldai6toslado7; + t_ab8500_codec_cr51_to_cr56_sltoda cr56_sltoda6; + + /* CR57 */ + t_ab8500_codec_cr57_bfifull_msk cr57_bfifull_msk; + t_ab8500_codec_cr57_bfiempt_msk cr57_bfiempt_msk; + t_ab8500_codec_cr57_dachan_msk cr57_dachan_msk; + t_ab8500_codec_cr57_gain_msk cr57_gain_msk; + t_ab8500_codec_cr57_dspad_msk cr57_dspad_msk; + t_ab8500_codec_cr57_dspda_msk cr57_dspda_msk; + t_ab8500_codec_cr57_stfir_msk cr57_stfir_msk; + + /* CR58 */ + t_ab8500_codec_cr58_bfifull_ev cr58_bfifull_ev; + t_ab8500_codec_cr58_bfiempt_ev cr58_bfiempt_ev; + t_ab8500_codec_cr58_dachan_ev cr58_dachan_ev; + t_ab8500_codec_cr58_gain_ev cr58_gain_ev; + t_ab8500_codec_cr58_dspad_ev cr58_dspad_ev; + t_ab8500_codec_cr58_dspda_ev cr58_dspda_ev; + t_ab8500_codec_cr58_stfir_ev cr58_stfir_ev; + + /* CR59 */ + t_ab8500_codec_cr59_vssready_msk cr59_vssready_msk; + t_ab8500_codec_cr59_shrtvibl_msk cr59_shrtvibl_msk; + t_ab8500_codec_cr59_shrtvibr_msk cr59_shrtvibr_msk; + t_ab8500_codec_cr59_shrthfl_msk cr59_shrthfl_msk; + t_ab8500_codec_cr59_shrthfr_msk cr59_shrthfr_msk; + t_ab8500_codec_cr59_shrthsl_msk cr59_shrthsl_msk; + t_ab8500_codec_cr59_shrthsr_msk cr59_shrthsr_msk; + t_ab8500_codec_cr59_shrtear_msk cr59_shrtear_msk; + + /* CR60 */ + t_ab8500_codec_cr60_vssready_ev cr60_vssready_ev; + t_ab8500_codec_cr60_shrtvibl_ev cr60_shrtvibl_ev; + t_ab8500_codec_cr60_shrtvibr_ev cr60_shrtvibr_ev; + t_ab8500_codec_cr60_shrthfl_ev cr60_shrthfl_ev; + t_ab8500_codec_cr60_shrthfr_ev cr60_shrthfr_ev; + t_ab8500_codec_cr60_shrthsl_ev cr60_shrthsl_ev; + t_ab8500_codec_cr60_shrthsr_ev cr60_shrthsr_ev; + t_ab8500_codec_cr60_shrtear_ev cr60_shrtear_ev; + + /* CR61 */ + t_ab8500_codec_cr61_revision cr61_revision; + t_ab8500_codec_cr61_fade_speed cr61_fade_speed; + + /* CR62 */ + t_ab8500_codec_cr62_dmic1sinc3 cr62_dmic1sinc3; + t_ab8500_codec_cr62_dmic2sinc3 cr62_dmic2sinc3; + t_ab8500_codec_cr62_dmic3sinc3 cr62_dmic3sinc3; + t_ab8500_codec_cr62_dmic4sinc3 cr62_dmic4sinc3; + t_ab8500_codec_cr62_dmic5sinc3 cr62_dmic5sinc3; + t_ab8500_codec_cr62_dmic6sinc3 cr62_dmic6sinc3; + + /* CR63 */ + t_ab8500_codec_cr63_datohslen cr63_datohslen; + t_ab8500_codec_cr63_datohsren cr63_datohsren; + t_ab8500_codec_cr63_ad1sel cr63_ad1sel; + t_ab8500_codec_cr63_ad2sel cr63_ad2sel; + t_ab8500_codec_cr63_ad3sel cr63_ad3sel; + t_ab8500_codec_cr63_ad5sel cr63_ad5sel; + t_ab8500_codec_cr63_ad6sel cr63_ad6sel; + t_ab8500_codec_cr63_ancsel cr63_ancsel; + + /* CR64 */ + t_ab8500_codec_cr64_datohfren cr64_datohfren; + t_ab8500_codec_cr64_datohflen cr64_datohflen; + t_ab8500_codec_cr64_hfrsel cr64_hfrsel; + t_ab8500_codec_cr64_hflsel cr64_hflsel; + t_ab8500_codec_cr64_stfir1sel cr64_stfir1sel; + t_ab8500_codec_cr64_stfir2sel cr64_stfir2sel; + + /* CR65 */ + t_ab8500_codec_cr65_fadedis_ad1 cr65_fadedis_ad1; + t_ab8500_codec_cr65_ad1gain cr65_ad1gain; + + /* CR66 */ + t_ab8500_codec_cr66_fadedis_ad2 cr66_fadedis_ad2; + t_ab8500_codec_cr66_ad2gain cr66_ad2gain; + + /* CR67 */ + t_ab8500_codec_cr67_fadedis_ad3 cr67_fadedis_ad3; + t_ab8500_codec_cr67_ad3gain cr67_ad3gain; + + /* CR68 */ + t_ab8500_codec_cr68_fadedis_ad4 cr68_fadedis_ad4; + t_ab8500_codec_cr68_ad4gain cr68_ad4gain; + + /* CR69 */ + t_ab8500_codec_cr69_fadedis_ad5 cr69_fadedis_ad5; + t_ab8500_codec_cr69_ad5gain cr69_ad5gain; + + /* CR70 */ + t_ab8500_codec_cr70_fadedis_ad6 cr70_fadedis_ad6; + t_ab8500_codec_cr70_ad6gain cr70_ad6gain; + + /* CR71 */ + t_ab8500_codec_cr71_fadedis_da1 cr71_fadedis_da1; + t_ab8500_codec_cr71_da1gain cr71_da1gain; + + /* CR72 */ + t_ab8500_codec_cr72_fadedis_da2 cr72_fadedis_da2; + t_ab8500_codec_cr72_da2gain cr72_da2gain; + + /* CR73 */ + t_ab8500_codec_cr73_fadedis_da3 cr73_fadedis_da3; + t_ab8500_codec_cr73_da3gain cr73_da3gain; + + /* CR74 */ + t_ab8500_codec_cr74_fadedis_da4 cr74_fadedis_da4; + t_ab8500_codec_cr74_da4gain cr74_da4gain; + + /* CR75 */ + t_ab8500_codec_cr75_fadedis_da5 cr75_fadedis_da5; + t_ab8500_codec_cr75_da5gain cr75_da5gain; + + /* CR76 */ + t_ab8500_codec_cr76_fadedis_da6 cr76_fadedis_da6; + t_ab8500_codec_cr76_da6gain cr76_da6gain; + + /* CR77 */ + t_ab8500_codec_cr77_fadedis_ad1l cr77_fadedis_ad1l; + t_ab8500_codec_cr77_ad1lbgain_to_hfl cr77_ad1lbgain_to_hfl; + + /* CR78 */ + t_ab8500_codec_cr78_fadedis_ad2l cr78_fadedis_ad2l; + t_ab8500_codec_cr78_ad2lbgain_to_hfr cr78_ad2lbgain_to_hfr; + + /* CR79 */ + t_ab8500_codec_cr79_hssinc1 cr79_hssinc1; + t_ab8500_codec_cr79_fadedis_hsl cr79_fadedis_hsl; + t_ab8500_codec_cr79_hsldgain cr79_hsldgain; + + /* CR80 */ + t_ab8500_codec_cr80_fadedis_hsr cr80_fadedis_hsr; + t_ab8500_codec_cr80_hsrdgain cr80_hsrdgain; + + /* CR81 */ + t_ab8500_codec_cr81_stfir1gain cr81_stfir1gain; + + /* CR82 */ + t_ab8500_codec_cr82_stfir2gain cr82_stfir2gain; + + /* CR83 */ + t_ab8500_codec_cr83_enanc cr83_enanc; + t_ab8500_codec_cr83_anciirinit cr83_anciirinit; + t_ab8500_codec_cr83_ancfirupdate cr83_ancfirupdate; + + /* CR84 */ + t_ab8500_codec_cr84_ancinshift cr84_ancinshift; + + /* CR85 */ + t_ab8500_codec_cr85_ancfiroutshift cr85_ancfiroutshift; + + /* CR86 */ + t_ab8500_codec_cr86_ancshiftout cr86_ancshiftout; + + /* CR87 */ + t_ab8500_codec_cr87_ancfircoeff_msb cr87_ancfircoeff_msb; + + /* CR88 */ + t_ab8500_codec_cr88_ancfircoeff_lsb cr88_ancfircoeff_lsb; + + /* CR89 */ + t_ab8500_codec_cr89_anciircoeff_msb cr89_anciircoeff_msb; + + /* CR90 */ + t_ab8500_codec_cr90_anciircoeff_lsb cr90_anciircoeff_lsb; + + /* CR91 */ + t_ab8500_codec_cr91_ancwarpdel_msb cr91_ancwarpdel_msb; + + /* CR92 */ + t_ab8500_codec_cr92_ancwarpdel_lsb cr92_ancwarpdel_lsb; + + /* CR93 */ + t_ab8500_codec_cr93_ancfirpeak_msb cr93_ancfirpeak_msb; + + /* CR94 */ + t_ab8500_codec_cr94_ancfirpeak_lsb cr94_ancfirpeak_lsb; + + /* CR95 */ + t_ab8500_codec_cr95_anciirpeak_msb cr95_anciirpeak_msb; + + /* CR96 */ + t_ab8500_codec_cr96_anciirpeak_lsb cr96_anciirpeak_lsb; + + /* CR97 */ + t_ab8500_codec_cr97_stfir_set cr97_stfir_set; + t_ab8500_codec_cr97_stfir_addr cr97_stfir_addr; + + /* CR98 */ + t_ab8500_codec_cr98_stfir_coeff_msb cr98_stfir_coeff_msb; + + /* CR99 */ + t_ab8500_codec_cr99_stfir_coeff_lsb cr99_stfir_coeff_lsb; + + /* CR100 */ + t_ab8500_codec_cr100_enstfirs cr100_enstfirs; + t_ab8500_codec_cr100_stfirstoif1 cr100_stfirstoif1; + t_ab8500_codec_cr100_stfir_busy cr100_stfir_busy; + + /* CR101 */ + t_ab8500_codec_cr101_parlhf cr101_parlhf; + t_ab8500_codec_cr101_parlvib cr101_parlvib; + t_ab8500_codec_cr101_classd_viblswapen cr101_classd_viblswapen; + t_ab8500_codec_cr101_classd_vibrswapen cr101_classd_vibrswapen; + t_ab8500_codec_cr101_classd_hflswapen cr101_classd_hflswapen; + t_ab8500_codec_cr101_classd_hfrswapen cr101_classd_hfrswapen; + + /* CR102 */ + t_ab8500_codec_cr102_classd_firbyp cr102_classd_firbyp; + t_ab8500_codec_cr102_classd_highvolen cr102_classd_highvolen; + + /* CR103 */ + t_ab8500_codec_cr103_classd_ditherhpgain cr103_classd_ditherhpgain; + t_ab8500_codec_cr103_classd_ditherwgain cr103_classd_ditherwgain; + + /* CR104 */ + t_ab8500_codec_cr104_bfifoint cr104_bfifoint; + + /* CR105 */ + t_ab8500_codec_cr105_bfifotx cr105_bfifotx; + + /* CR106 */ + t_ab8500_codec_cr106_bfifofsext cr106_bfifofsext; + t_ab8500_codec_cr106_bfifomsk cr106_bfifomsk; + t_ab8500_codec_cr106_bfifomstr cr106_bfifomstr; + t_ab8500_codec_cr106_bfifostrt cr106_bfifostrt; + + /* CR107 */ + t_ab8500_codec_cr107_bfifosampnr cr107_bfifosampnr; + + /* CR108 */ + t_ab8500_codec_cr108_bfifowakeup cr108_bfifowakeup; + + /* CR109 */ + t_ab8500_codec_cr109_bfifosamples cr109_bfifosamples; + +} t_ab8500_codec_configuration; + +typedef enum { + AB8500_CODEC_DIRECTION_IN, + AB8500_CODEC_DIRECTION_OUT, + AB8500_CODEC_DIRECTION_INOUT +} t_ab8500_codec_direction; + +typedef enum { + AB8500_CODEC_MODE_HIFI, + AB8500_CODEC_MODE_VOICE, + AB8500_CODEC_MODE_MANUAL_SETTING +} t_ab8500_codec_mode; + +typedef enum { + AB8500_CODEC_AUDIO_INTERFACE_0, + AB8500_CODEC_AUDIO_INTERFACE_1 +} t_ab8500_codec_audio_interface; + +typedef enum { + AB8500_CODEC_SRC_LINEIN, + AB8500_CODEC_SRC_MICROPHONE_1A, + AB8500_CODEC_SRC_MICROPHONE_1B, + AB8500_CODEC_SRC_MICROPHONE_2, + AB8500_CODEC_SRC_D_MICROPHONE_1, + AB8500_CODEC_SRC_D_MICROPHONE_2, + AB8500_CODEC_SRC_D_MICROPHONE_3, + AB8500_CODEC_SRC_D_MICROPHONE_4, + AB8500_CODEC_SRC_D_MICROPHONE_5, + AB8500_CODEC_SRC_D_MICROPHONE_6, + AB8500_CODEC_SRC_FM_RX, + AB8500_CODEC_SRC_ALL +} t_ab8500_codec_src; + +typedef enum { + AB8500_CODEC_DEST_HEADSET, + AB8500_CODEC_DEST_EARPIECE, + AB8500_CODEC_DEST_HANDSFREE, + AB8500_CODEC_DEST_VIBRATOR_L, + AB8500_CODEC_DEST_VIBRATOR_R, + AB8500_CODEC_DEST_ALL +} t_ab8500_codec_dest; + +typedef struct { + t_uint8 slave_address_of_ab8500_codec; + t_ab8500_codec_direction ab8500_codec_direction; + t_ab8500_codec_mode ab8500_codec_mode_in; + t_ab8500_codec_mode ab8500_codec_mode_out; + t_ab8500_codec_audio_interface audio_interface; + t_ab8500_codec_src ab8500_codec_src; + t_ab8500_codec_dest ab8500_codec_dest; + t_uint8 in_left_volume; + t_uint8 in_right_volume; + t_uint8 out_left_volume; + t_uint8 out_right_volume; + + t_ab8500_codec_configuration ab8500_codec_configuration; +} t_ab8500_codec_system_context; +#endif /* _AB8500_CODECP_H_ */ + +/* End of file AB8500_CODECP.h */ diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h new file mode 100644 index 00000000000..866cd0c80f1 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h @@ -0,0 +1,3037 @@ +/*****************************************************************************/ +/** +* © ST-Ericsson, 2009 - All rights reserved +* Reproduction and Communication of this document is strictly prohibited +* unless specifically authorized in writing by ST-Ericsson +* +* \brief Private Header file for AB8500 CODEC +* \author ST-Ericsson +*/ +/*****************************************************************************/ + +#ifndef _AB8500_CODECP_V1_0_H_ +#define _AB8500_CODECP_V1_0_H_ + +/*---------------------------------------------------------------------------- + * Includes + *---------------------------------------------------------------------------*/ +#include "hcl_defs.h" + +#define AB8500_CODEC_HCL_VERSION_ID 3 +#define AB8500_CODEC_HCL_MAJOR_ID 0 +#define AB8500_CODEC_HCL_MINOR_ID 0 + +#define AB8500_CODEC_MASK_ONE_BIT 0x1UL +#define AB8500_CODEC_MASK_TWO_BITS 0x3UL +#define AB8500_CODEC_MASK_THREE_BITS 0x7UL +#define AB8500_CODEC_MASK_FOUR_BITS 0xFUL +#define AB8500_CODEC_MASK_FIVE_BITS 0x1FUL +#define AB8500_CODEC_MASK_SIX_BITS 0x3FUL +#define AB8500_CODEC_MASK_SEVEN_BITS 0x7FUL +#define AB8500_CODEC_MASK_EIGHT_BITS 0xFFUL + +#define AB8500_CODEC_WRITE_BITS(reg, val, bit_nb, pos) (reg) = ((t_uint8) ((((reg) & (~(bit_nb << pos))) | (((val) & bit_nb) << pos)))) + +#define AB8500_CODEC_BLOCK 0x0D + +#define AB8500_CODEC_MASK_TWO_MS_BITS 0xC0UL +#define AB8500_CODEC_MASK_SIX_LS_BITS 0x3FUL + +/* Genepi AudioCodec Control Registers */ + +#define AB8500_CODEC_CR0 0x00 +#define AB8500_CODEC_CR1 0x01 +#define AB8500_CODEC_CR2 0x02 +#define AB8500_CODEC_CR3 0x03 +#define AB8500_CODEC_CR4 0x04 +#define AB8500_CODEC_CR5 0x05 +#define AB8500_CODEC_CR6 0x06 +#define AB8500_CODEC_CR7 0x07 +#define AB8500_CODEC_CR8 0x08 +#define AB8500_CODEC_CR9 0x09 +#define AB8500_CODEC_CR10 0x0A +#define AB8500_CODEC_CR11 0x0B +#define AB8500_CODEC_CR12 0x0C +#define AB8500_CODEC_CR13 0x0D +#define AB8500_CODEC_CR14 0x0E +#define AB8500_CODEC_CR15 0x0F +#define AB8500_CODEC_CR16 0x10 +#define AB8500_CODEC_CR17 0x11 +#define AB8500_CODEC_CR18 0x12 +#define AB8500_CODEC_CR19 0x13 +#define AB8500_CODEC_CR20 0x14 +#define AB8500_CODEC_CR21 0x15 +#define AB8500_CODEC_CR22 0x16 +#define AB8500_CODEC_CR23 0x17 +#define AB8500_CODEC_CR24 0x18 +#define AB8500_CODEC_CR25 0x19 +#define AB8500_CODEC_CR26 0x1A +#define AB8500_CODEC_CR27 0x1B +#define AB8500_CODEC_CR28 0x1C +#define AB8500_CODEC_CR29 0x1D +#define AB8500_CODEC_CR30 0x1E +#define AB8500_CODEC_CR31 0x1F +#define AB8500_CODEC_CR32 0x20 +#define AB8500_CODEC_CR33 0x21 +#define AB8500_CODEC_CR34 0x22 +#define AB8500_CODEC_CR35 0x23 +#define AB8500_CODEC_CR36 0x24 +#define AB8500_CODEC_CR37 0x25 +#define AB8500_CODEC_CR38 0x26 +#define AB8500_CODEC_CR39 0x27 +#define AB8500_CODEC_CR40 0x28 +#define AB8500_CODEC_CR41 0x29 +#define AB8500_CODEC_CR42 0x2A +#define AB8500_CODEC_CR43 0x2B +#define AB8500_CODEC_CR44 0x2C +#define AB8500_CODEC_CR45 0x2D +#define AB8500_CODEC_CR46 0x2E +#define AB8500_CODEC_CR47 0x2F +#define AB8500_CODEC_CR48 0x30 +#define AB8500_CODEC_CR49 0x31 +#define AB8500_CODEC_CR50 0x32 +#define AB8500_CODEC_CR51 0x33 +#define AB8500_CODEC_CR52 0x34 +#define AB8500_CODEC_CR53 0x35 +#define AB8500_CODEC_CR54 0x36 +#define AB8500_CODEC_CR55 0x37 +#define AB8500_CODEC_CR56 0x38 +#define AB8500_CODEC_CR57 0x39 +#define AB8500_CODEC_CR58 0x3A +#define AB8500_CODEC_CR59 0x3B +#define AB8500_CODEC_CR60 0x3C +#define AB8500_CODEC_CR61 0x3D +#define AB8500_CODEC_CR62 0x3E +#define AB8500_CODEC_CR63 0x3F +#define AB8500_CODEC_CR64 0x40 +#define AB8500_CODEC_CR65 0x41 +#define AB8500_CODEC_CR66 0x42 +#define AB8500_CODEC_CR67 0x43 +#define AB8500_CODEC_CR68 0x44 +#define AB8500_CODEC_CR69 0x45 +#define AB8500_CODEC_CR70 0x46 +#define AB8500_CODEC_CR71 0x47 +#define AB8500_CODEC_CR72 0x48 +#define AB8500_CODEC_CR73 0x49 +#define AB8500_CODEC_CR74 0x4A +#define AB8500_CODEC_CR75 0x4B +#define AB8500_CODEC_CR76 0x4C +#define AB8500_CODEC_CR77 0x4D +#define AB8500_CODEC_CR78 0x4E +#define AB8500_CODEC_CR79 0x4F +#define AB8500_CODEC_CR80 0x50 +#define AB8500_CODEC_CR81 0x51 +#define AB8500_CODEC_CR82 0x52 +#define AB8500_CODEC_CR83 0x53 +#define AB8500_CODEC_CR84 0x54 +#define AB8500_CODEC_CR85 0x55 +#define AB8500_CODEC_CR86 0x56 +#define AB8500_CODEC_CR87 0x57 +#define AB8500_CODEC_CR88 0x58 +#define AB8500_CODEC_CR89 0x59 +#define AB8500_CODEC_CR90 0x5A +#define AB8500_CODEC_CR91 0x5B +#define AB8500_CODEC_CR92 0x5C +#define AB8500_CODEC_CR93 0x5D +#define AB8500_CODEC_CR94 0x5E +#define AB8500_CODEC_CR95 0x5F +#define AB8500_CODEC_CR96 0x60 +#define AB8500_CODEC_CR97 0x61 +#define AB8500_CODEC_CR98 0x62 +#define AB8500_CODEC_CR99 0x63 +#define AB8500_CODEC_CR100 0x64 +#define AB8500_CODEC_CR101 0x65 +#define AB8500_CODEC_CR102 0x66 +#define AB8500_CODEC_CR103 0x67 +#define AB8500_CODEC_CR104 0x68 +#define AB8500_CODEC_CR105 0x69 +#define AB8500_CODEC_CR106 0x6A +#define AB8500_CODEC_CR107 0x6B +#define AB8500_CODEC_CR108 0x6C +#define AB8500_CODEC_CR109 0x6D +#define AB8500_CODEC_CR110 0x6E +#define AB8500_CODEC_CR111 0x6F + +/* CR0-CR0x0000 */ +#define AB8500_CODEC_CR0_POWERUP 7 +#define AB8500_CODEC_CR0_ENAANA 3 + +/* CR1-CR0x0001 */ +#define AB8500_CODEC_CR1_SWRESET 7 + +/* CR2-CR0x0002 */ +#define AB8500_CODEC_CR2_ENAD1 7 +#define AB8500_CODEC_CR2_ENAD2 6 +#define AB8500_CODEC_CR2_ENAD3 5 +#define AB8500_CODEC_CR2_ENAD4 4 +#define AB8500_CODEC_CR2_ENAD5 3 +#define AB8500_CODEC_CR2_ENAD6 2 + +/* CR3-CR0x0003 */ +#define AB8500_CODEC_CR3_ENDA1 7 +#define AB8500_CODEC_CR3_ENDA2 6 +#define AB8500_CODEC_CR3_ENDA3 5 +#define AB8500_CODEC_CR3_ENDA4 4 +#define AB8500_CODEC_CR3_ENDA5 3 +#define AB8500_CODEC_CR3_ENDA6 2 + +/* CR4-CR0x0004 */ +#define AB8500_CODEC_CR4_LOWPOWHS 7 +#define AB8500_CODEC_CR4_LOWPOWDACHS 5 +#define AB8500_CODEC_CR4_LOWPOWEAR 4 +#define AB8500_CODEC_CR4_EAR_SEL_CM 2 +#define AB8500_CODEC_CR4_HS_HP_EN 1 + +/* CR5-CR0x0005 */ +#define AB8500_CODEC_CR5_ENMIC1 7 +#define AB8500_CODEC_CR5_ENMIC2 6 +#define AB8500_CODEC_CR5_ENLINL 5 +#define AB8500_CODEC_CR5_ENLINR 4 +#define AB8500_CODEC_CR5_MUTMIC1 3 +#define AB8500_CODEC_CR5_MUTMIC2 2 +#define AB8500_CODEC_CR5_MUTELINL 1 +#define AB8500_CODEC_CR5_MUTELINR 0 + +/* CR6-CR0x0006 */ +#define AB8500_CODEC_CR6_ENDMIC1 7 +#define AB8500_CODEC_CR6_ENDMIC2 6 +#define AB8500_CODEC_CR6_ENDMIC3 5 +#define AB8500_CODEC_CR6_ENDMIC4 4 +#define AB8500_CODEC_CR6_ENDMIC5 3 +#define AB8500_CODEC_CR6_ENDMIC6 2 + +/* CR7-CR0x0007 */ +#define AB8500_CODEC_CR7_MIC1SEL 7 +#define AB8500_CODEC_CR7_LINRSEL 6 +#define AB8500_CODEC_CR7_ENDRVHSL 5 +#define AB8500_CODEC_CR7_ENDRVHSR 4 +#define AB8500_CODEC_CR7_ENADCMIC 2 +#define AB8500_CODEC_CR7_ENADCLINL 1 +#define AB8500_CODEC_CR7_ENADCLINR 0 + +/* CR8-CR0x0008 */ +#define AB8500_CODEC_CR8_CP_DIS_PLDWN 7 +#define AB8500_CODEC_CR8_ENEAR 6 +#define AB8500_CODEC_CR8_ENHSL 5 +#define AB8500_CODEC_CR8_ENHSR 4 +#define AB8500_CODEC_CR8_ENHFL 3 +#define AB8500_CODEC_CR8_ENHFR 2 +#define AB8500_CODEC_CR8_ENVIBL 1 +#define AB8500_CODEC_CR8_ENVIBR 0 + +/* CR9-CR0x0009 */ +#define AB8500_CODEC_CR9_ENADACEAR 6 +#define AB8500_CODEC_CR9_ENADACHSL 5 +#define AB8500_CODEC_CR9_ENADACHSR 4 +#define AB8500_CODEC_CR9_ENADACHFL 3 +#define AB8500_CODEC_CR9_ENADACHFR 2 +#define AB8500_CODEC_CR9_ENADACVIBL 1 +#define AB8500_CODEC_CR9_ENADACVIBR 0 + +/* CR10-CR0x000A */ +#define AB8500_CODEC_CR10_MUTEEAR 6 +#define AB8500_CODEC_CR10_MUTEHSL 5 +#define AB8500_CODEC_CR10_MUTEHSR 4 + +/* CR11-CR0x000B */ +#define AB8500_CODEC_CR11_ENSHORTPWD 7 +#define AB8500_CODEC_CR11_EARSHORTDIS 6 +#define AB8500_CODEC_CR11_HSSHORTDIS 5 +#define AB8500_CODEC_CR11_HSPULLDEN 4 +#define AB8500_CODEC_CR11_HSOSCEN 2 +#define AB8500_CODEC_CR11_HSFADEN 1 +#define AB8500_CODEC_CR11_HSZCDDIS 0 + +/* CR12-CR0x000C */ +#define AB8500_CODEC_CR12_ENCPHS 7 +#define AB8500_CODEC_CR12_HSAUTOEN 0 + +/* CR13-CR0x000D */ +#define AB8500_CODEC_CR13_ENVDET_HTHRESH 4 +#define AB8500_CODEC_CR13_ENVDET_LTHRESH 0 + +/* CR14-CR0x000E */ +#define AB8500_CODEC_CR14_SMPSLVEN 7 +#define AB8500_CODEC_CR14_ENVDETSMPSEN 6 +#define AB8500_CODEC_CR14_CPLVEN 5 +#define AB8500_CODEC_CR14_ENVDETCPEN 4 +#define AB8500_CODEC_CR14_ENVDET_TIME 0 + +/* CR15-CR0x000F */ +#define AB8500_CODEC_CR15_PWMTOVIBL 7 +#define AB8500_CODEC_CR15_PWMTOVIBR 6 +#define AB8500_CODEC_CR15_PWMLCTRL 5 +#define AB8500_CODEC_CR15_PWMRCTRL 4 +#define AB8500_CODEC_CR15_PWMNLCTRL 3 +#define AB8500_CODEC_CR15_PWMPLCTRL 2 +#define AB8500_CODEC_CR15_PWMNRCTRL 1 +#define AB8500_CODEC_CR15_PWMPRCTRL 0 + +/* CR16-CR0x0010 */ +#define AB8500_CODEC_CR16_PWMNLPOL 7 +#define AB8500_CODEC_CR16_PWMNLDUTYCYCLE 0 + +/* CR17-CR0x0011 */ +#define AB8500_CODEC_CR17_PWMPLPOL 7 +#define AB8500_CODEC_CR17_PWMLPDUTYCYCLE 0 + +/* CR18-CR0x0012 */ +#define AB8500_CODEC_CR18_PWMNRPOL 7 +#define AB8500_CODEC_CR18_PWMNRDUTYCYCLE 0 + +/* CR19-CR0x0013 */ +#define AB8500_CODEC_CR19_PWMPRPOL 7 +#define AB8500_CODEC_CR19_PWMRPDUTYCYCLE 0 + +/* CR20-CR0x0014 */ +#define AB8500_CODEC_CR20_EN_SE_MIC1 7 +#define AB8500_CODEC_CR20_LOW_POW_MIC1 6 +#define AB8500_CODEC_CR20_MIC1_GAIN 0 + +/* CR21-CR0x0015 */ +#define AB8500_CODEC_CR21_EN_SE_MIC2 7 +#define AB8500_CODEC_CR21_LOW_POW_MIC2 6 +#define AB8500_CODEC_CR21_MIC2_GAIN 0 + +/* CR22-CR0x0016 */ +#define AB8500_CODEC_CR22_HSL_GAIN 4 +#define AB8500_CODEC_CR22_HSR_GAIN 0 + +/* CR23-CR0x0017 */ +#define AB8500_CODEC_CR23_LINL_GAIN 4 +#define AB8500_CODEC_CR23_LINR_GAIN 0 + +/* CR24-CR0x0018 */ +#define AB8500_CODEC_CR24_LINTOHSL_GAIN 0 + +/* CR25-CR0x0019 */ +#define AB8500_CODEC_CR25_LINTOHSR_GAIN 0 + +/* CR26-CR0x001A */ +#define AB8500_CODEC_CR26_AD1NH 7 +#define AB8500_CODEC_CR26_AD2NH 6 +#define AB8500_CODEC_CR26_AD3NH 5 +#define AB8500_CODEC_CR26_AD4NH 4 +#define AB8500_CODEC_CR26_AD1_VOICE 3 +#define AB8500_CODEC_CR26_AD2_VOICE 2 +#define AB8500_CODEC_CR26_AD3_VOICE 1 +#define AB8500_CODEC_CR26_AD4_VOICE 0 + +/* CR27-CR0x001B */ +#define AB8500_CODEC_CR27_EN_MASTGEN 7 +#define AB8500_CODEC_CR27_IF1_BITCLK_OSR 5 +#define AB8500_CODEC_CR27_ENFS_BITCLK1 4 +#define AB8500_CODEC_CR27_IF0_BITCLK_OSR 1 +#define AB8500_CODEC_CR27_ENFS_BITCLK0 0 + +/* CR28-CR0x001C */ +#define AB8500_CODEC_CR28_FSYNC0P 6 +#define AB8500_CODEC_CR28_BITCLK0P 5 +#define AB8500_CODEC_CR28_IF0DEL 4 +#define AB8500_CODEC_CR28_IF0FORMAT 2 +#define AB8500_CODEC_CR28_IF0WL 0 + +/* CR29-CR0x001D */ +#define AB8500_CODEC_CR29_IF0DATOIF1AD 7 +#define AB8500_CODEC_CR29_IF0CKTOIF1CK 6 +#define AB8500_CODEC_CR29_IF1MASTER 5 +#define AB8500_CODEC_CR29_IF1DATOIF0AD 3 +#define AB8500_CODEC_CR29_IF1CKTOIF0CK 2 +#define AB8500_CODEC_CR29_IF0MASTER 1 +#define AB8500_CODEC_CR29_IF0BFIFOEN 0 + +/* CR30-CR0x001E */ +#define AB8500_CODEC_CR30_FSYNC1P 6 +#define AB8500_CODEC_CR30_BITCLK1P 5 +#define AB8500_CODEC_CR30_IF1DEL 4 +#define AB8500_CODEC_CR30_IF1FORMAT 2 +#define AB8500_CODEC_CR30_IF1WL 0 + +/* CR31-CR0x001F */ +#define AB8500_CODEC_CR31_ADOTOSLOT1 4 +#define AB8500_CODEC_CR31_ADOTOSLOT0 0 + +/* CR32-CR0x0020 */ +#define AB8500_CODEC_CR32_ADOTOSLOT3 4 +#define AB8500_CODEC_CR32_ADOTOSLOT2 0 + +/* CR33-CR0x0021 */ +#define AB8500_CODEC_CR33_ADOTOSLOT5 4 +#define AB8500_CODEC_CR33_ADOTOSLOT4 0 + +/* CR34-CR0x0022 */ +#define AB8500_CODEC_CR34_ADOTOSLOT7 4 +#define AB8500_CODEC_CR34_ADOTOSLOT6 0 + +/* CR35-CR0x0023 */ +#define AB8500_CODEC_CR35_ADOTOSLOT9 4 +#define AB8500_CODEC_CR35_ADOTOSLOT8 0 + +/* CR36-CR0x0024 */ +#define AB8500_CODEC_CR36_ADOTOSLOT11 4 +#define AB8500_CODEC_CR36_ADOTOSLOT10 0 + +/* CR37-CR0x0025 */ +#define AB8500_CODEC_CR37_ADOTOSLOT13 4 +#define AB8500_CODEC_CR37_ADOTOSLOT12 0 + +/* CR38-CR0x0026 */ +#define AB8500_CODEC_CR38_ADOTOSLOT15 4 +#define AB8500_CODEC_CR38_ADOTOSLOT14 0 + +/* CR39-CR0x0027 */ +#define AB8500_CODEC_CR39_ADOTOSLOT17 4 +#define AB8500_CODEC_CR39_ADOTOSLOT16 0 + +/* CR40-CR0x0028 */ +#define AB8500_CODEC_CR40_ADOTOSLOT19 4 +#define AB8500_CODEC_CR40_ADOTOSLOT18 0 + +/* CR41-CR0x0029 */ +#define AB8500_CODEC_CR41_ADOTOSLOT21 4 +#define AB8500_CODEC_CR41_ADOTOSLOT20 0 + +/* CR42-CR0x002A */ +#define AB8500_CODEC_CR42_ADOTOSLOT23 4 +#define AB8500_CODEC_CR42_ADOTOSLOT22 0 + +/* CR43-CR0x002B */ +#define AB8500_CODEC_CR43_ADOTOSLOT25 4 +#define AB8500_CODEC_CR43_ADOTOSLOT24 0 + +/* CR44-CR0x002C */ +#define AB8500_CODEC_CR44_ADOTOSLOT27 4 +#define AB8500_CODEC_CR44_ADOTOSLOT26 0 + +/* CR45-CR0x002D */ +#define AB8500_CODEC_CR45_ADOTOSLOT29 4 +#define AB8500_CODEC_CR45_ADOTOSLOT28 0 + +/* CR46-CR0x002E */ +#define AB8500_CODEC_CR46_ADOTOSLOT31 4 +#define AB8500_CODEC_CR46_ADOTOSLOT30 0 + +/* CR47-CR0x002F */ +#define AB8500_CODEC_CR47_HIZ_SL7 7 +#define AB8500_CODEC_CR47_HIZ_SL6 6 +#define AB8500_CODEC_CR47_HIZ_SL5 5 +#define AB8500_CODEC_CR47_HIZ_SL4 4 +#define AB8500_CODEC_CR47_HIZ_SL3 3 +#define AB8500_CODEC_CR47_HIZ_SL2 2 +#define AB8500_CODEC_CR47_HIZ_SL1 1 +#define AB8500_CODEC_CR47_HIZ_SL0 0 + +/* CR48-CR0x0030 */ +#define AB8500_CODEC_CR48_HIZ_SL15 7 +#define AB8500_CODEC_CR48_HIZ_SL14 6 +#define AB8500_CODEC_CR48_HIZ_SL13 5 +#define AB8500_CODEC_CR48_HIZ_SL12 4 +#define AB8500_CODEC_CR48_HIZ_SL11 3 +#define AB8500_CODEC_CR48_HIZ_SL10 2 +#define AB8500_CODEC_CR48_HIZ_SL9 1 +#define AB8500_CODEC_CR48_HIZ_SL8 0 + +/* CR49-CR0x0031 */ +#define AB8500_CODEC_CR49_HIZ_SL23 7 +#define AB8500_CODEC_CR49_HIZ_SL22 6 +#define AB8500_CODEC_CR49_HIZ_SL21 5 +#define AB8500_CODEC_CR49_HIZ_SL20 4 +#define AB8500_CODEC_CR49_HIZ_SL19 3 +#define AB8500_CODEC_CR49_HIZ_SL18 2 +#define AB8500_CODEC_CR49_HIZ_SL17 1 +#define AB8500_CODEC_CR49_HIZ_SL16 0 + +/* CR50-CR0x0032 */ +#define AB8500_CODEC_CR50_HIZ_SL31 7 +#define AB8500_CODEC_CR50_HIZ_SL30 6 +#define AB8500_CODEC_CR50_HIZ_SL29 5 +#define AB8500_CODEC_CR50_HIZ_SL28 4 +#define AB8500_CODEC_CR50_HIZ_SL27 3 +#define AB8500_CODEC_CR50_HIZ_SL26 2 +#define AB8500_CODEC_CR50_HIZ_SL25 1 +#define AB8500_CODEC_CR50_HIZ_SL24 0 + +/* CR51-CR0x0033 */ +#define AB8500_CODEC_CR51_DA12_VOICE 7 +#define AB8500_CODEC_CR51_SWAP_DA12_34 6 +#define AB8500_CODEC_CR51_SLDAI7TOSLADO1 5 +#define AB8500_CODEC_CR51_SLTODA1 0 + +/* CR52-CR0x0034 */ +#define AB8500_CODEC_CR52_SLDAI8TOSLADO2 5 +#define AB8500_CODEC_CR52_SLTODA2 0 + +/* CR53-CR0x0035 */ +#define AB8500_CODEC_CR53_DA34_VOICE 7 +#define AB8500_CODEC_CR53_SLDAI7TOSLADO3 5 +#define AB8500_CODEC_CR53_SLTODA3 0 + +/* CR54-CR0x0036 */ +#define AB8500_CODEC_CR54_SLDAI8TOSLADO4 5 +#define AB8500_CODEC_CR54_SLTODA4 0 + +/* CR55-CR0x0037 */ +#define AB8500_CODEC_CR55_DA56_VOICE 7 +#define AB8500_CODEC_CR55_SLDAI7TOSLADO5 5 +#define AB8500_CODEC_CR55_SLTODA5 0 + +/* CR56-CR0x0038 */ +#define AB8500_CODEC_CR56_SLDAI8TOSLADO6 5 +#define AB8500_CODEC_CR56_SLTODA6 0 + +/* CR57-CR0x0039 */ +#define AB8500_CODEC_CR57_SLDAI8TOSLADO7 5 +#define AB8500_CODEC_CR57_SLTODA7 0 + +/* CR58-CR0x003A */ +#define AB8500_CODEC_CR58_SLDAI7TOSLADO8 5 +#define AB8500_CODEC_CR58_SLTODA8 0 + +/* CR59-CR0x003B */ +#define AB8500_CODEC_CR59_PARLHF 7 +#define AB8500_CODEC_CR59_PARLVIB 6 +#define AB8500_CODEC_CR59_CLASSDVIB1SWAPEN 3 +#define AB8500_CODEC_CR59_CLASSDVIB2SWAPEN 2 +#define AB8500_CODEC_CR59_CLASSDHFLSWAPEN 1 +#define AB8500_CODEC_CR59_CLASSDHFRSWAPEN 0 + +/* CR60-CR0x003C */ +#define AB8500_CODEC_CR60_CLASSD_FIR_BYP 4 +#define AB8500_CODEC_CR60_CLASSD_HIGHVOL_EN 0 + +/* CR61-CR0x003D */ +#define AB8500_CODEC_CR61_CLASSD_DITH_HPGAIN 4 +#define AB8500_CODEC_CR61_CLASSD_DITH_WGAIN 0 + +/* CR62-CR0x003E */ +#define AB8500_CODEC_CR62_DMIC1SINC3 5 +#define AB8500_CODEC_CR62_DMIC2SINC3 4 +#define AB8500_CODEC_CR62_DMIC3SINC3 3 +#define AB8500_CODEC_CR62_DMIC4SINC3 2 +#define AB8500_CODEC_CR62_DMIC5SINC3 1 +#define AB8500_CODEC_CR62_DMIC6SINC3 0 + +/* CR63-CR0x003F */ +#define AB8500_CODEC_CR63_DATOHSLEN 7 +#define AB8500_CODEC_CR63_DATOHSREN 6 +#define AB8500_CODEC_CR63_AD1SEL 5 +#define AB8500_CODEC_CR63_AD2SEL 4 +#define AB8500_CODEC_CR63_AD3SEL 3 +#define AB8500_CODEC_CR63_AD5SEL 2 +#define AB8500_CODEC_CR63_AD6SEL 1 +#define AB8500_CODEC_CR63_ANCSEL 0 + +/* CR64-CR0x0040 */ +#define AB8500_CODEC_CR64_DATOHFREN 7 +#define AB8500_CODEC_CR64_DATOHFLEN 6 +#define AB8500_CODEC_CR64_HFRSEL 5 +#define AB8500_CODEC_CR64_HFLSEL 4 +#define AB8500_CODEC_CR64_STFIR1SEL 2 +#define AB8500_CODEC_CR64_STFIR2SEL 0 + +/* CR65-CR0x0041 */ +#define AB8500_CODEC_CR65_FADEDIS_AD1 6 +#define AB8500_CODEC_CR65_AD1GAIN 0 + +/* CR66-CR0x0042 */ +#define AB8500_CODEC_CR66_FADEDIS_AD2 6 +#define AB8500_CODEC_CR66_AD2GAIN 0 + +/* CR67-CR0x0043 */ +#define AB8500_CODEC_CR67_FADEDIS_AD3 6 +#define AB8500_CODEC_CR67_AD3GAIN 0 + +/* CR68-CR0x0044 */ +#define AB8500_CODEC_CR68_FADEDIS_AD4 6 +#define AB8500_CODEC_CR68_AD4GAIN 0 + +/* CR69-CR0x0045 */ +#define AB8500_CODEC_CR69_FADEDIS_AD5 6 +#define AB8500_CODEC_CR69_AD5GAIN 0 + +/* CR70-CR0x0046 */ +#define AB8500_CODEC_CR70_FADEDIS_AD6 6 +#define AB8500_CODEC_CR70_AD6GAIN 0 + +/* CR71-CR0x0047 */ +#define AB8500_CODEC_CR71_FADEDIS_DA1 6 +#define AB8500_CODEC_CR71_DA1GAIN 0 + +/* CR72-CR0x0048 */ +#define AB8500_CODEC_CR72_FADEDIS_DA2 6 +#define AB8500_CODEC_CR72_DA2GAIN 0 + +/* CR73-CR0x0049 */ +#define AB8500_CODEC_CR73_FADEDIS_DA3 6 +#define AB8500_CODEC_CR73_DA3GAIN 0 + +/* CR74-CR0x004A */ +#define AB8500_CODEC_CR74_FADEDIS_DA4 6 +#define AB8500_CODEC_CR74_DA4GAIN 0 + +/* CR75-CR0x004B */ +#define AB8500_CODEC_CR75_FADEDIS_DA5 6 +#define AB8500_CODEC_CR75_DA5GAIN 0 + +/* CR76-CR0x004C */ +#define AB8500_CODEC_CR76_FADEDIS_DA6 6 +#define AB8500_CODEC_CR76_DA6GAIN 0 + +/* CR77-CR0x004D */ +#define AB8500_CODEC_CR77_FADEDIS_AD1L 6 +#define AB8500_CODEC_CR77_AD1LBGAIN 0 + +/* CR78-CR0x004E */ +#define AB8500_CODEC_CR78_FADEDIS_AD2L 6 +#define AB8500_CODEC_CR78_AD2LBGAIN 0 + +/* CR79-CR0x004F */ +#define AB8500_CODEC_CR79_HSSINC1 7 +#define AB8500_CODEC_CR79_FADEDIS_HSL 4 +#define AB8500_CODEC_CR79_HSLDGAIN 0 + +/* CR80-CR0x0050 */ +#define AB8500_CODEC_CR80_FADE_SPEED 6 +#define AB8500_CODEC_CR80_FADEDIS_HSR 4 +#define AB8500_CODEC_CR80_HSRDGAIN 0 + +/* CR81-CR0x0051 */ +#define AB8500_CODEC_CR81_STFIR1GAIN 0 + +/* CR82-CR0x0052 */ +#define AB8500_CODEC_CR82_STFIR2GAIN 0 + +/* CR83-CR0x0053 */ +#define AB8500_CODEC_CR83_ENANC 2 +#define AB8500_CODEC_CR83_ANCIIRINIT 1 +#define AB8500_CODEC_CR83_ANCFIRUPDATE 0 + +/* CR84-CR0x0054 */ +#define AB8500_CODEC_CR84_ANCINSHIFT 0 + +/* CR85-CR0x0055 */ +#define AB8500_CODEC_CR85_ANCFIROUTSHIFT 0 + +/* CR86-CR0x0056 */ +#define AB8500_CODEC_CR86_ANCSHIFTOUT 0 + +/* CR87-CR0x0057 */ +#define AB8500_CODEC_CR87_ANCFIRCOEFF_MSB 0 + +/* CR88-CR0x0058 */ +#define AB8500_CODEC_CR88_ANCFIRCOEFF_LSB 0 + +/* CR89-CR0x0059 */ +#define AB8500_CODEC_CR89_ANCIIRCOEFF_MSB 0 + +/* CR90-CR0x005A */ +#define AB8500_CODEC_CR90_ANCIIRCOEFF_LSB 0 + +/* CR91-CR0x005B */ +#define AB8500_CODEC_CR91_ANCWARPDEL_MSB 0 + +/* CR92-CR0x005C */ +#define AB8500_CODEC_CR92_ANCWARPDEL_LSB 0 + +/* CR93-CR0x005D */ +#define AB8500_CODEC_CR93_ANCFIRPEAK_MSB 0 + +/* CR94-CR0x005E */ +#define AB8500_CODEC_CR94_ANCFIRPEAK_LSB 0 + +/* CR95-CR0x005F */ +#define AB8500_CODEC_CR95_ANCIIRPEAK_MSB 0 + +/* CR96-CR0x0060 */ +#define AB8500_CODEC_CR96_ANCIIRPEAK_LSB 0 + +/* CR97-CR0x0061 */ +#define AB8500_CODEC_CR97_STFIR_SET 7 +#define AB8500_CODEC_CR97_STFIR_ADDR 0 + +/* CR98-CR0x0062 */ +#define AB8500_CODEC_CR98_STFIR_COEFF_MSB 0 + +/* CR99-CR0x0063 */ +#define AB8500_CODEC_CR99_STFIR_COEFF_LSB 0 + +/* CR100-CR0x0064 */ +#define AB8500_CODEC_CR100_ENSTFIRS 2 +#define AB8500_CODEC_CR100_STFIRSTOIF1 1 +#define AB8500_CODEC_CR100_STFIR_BUSY 0 + +/* CR101-CR0x0065 */ +#define AB8500_CODEC_CR101_HSOFFSTMASK 7 +#define AB8500_CODEC_CR101_FIFOFULLMASK 6 +#define AB8500_CODEC_CR101_FIFOEMPTYMASK 5 +#define AB8500_CODEC_CR101_DASATMASK 4 +#define AB8500_CODEC_CR101_ADSATMASK 3 +#define AB8500_CODEC_CR101_ADDSPMASK 2 +#define AB8500_CODEC_CR101_DADSPMASK 1 +#define AB8500_CODEC_CR101_FIRSIDMASK 0 + +/* CR102-CR0x0066 */ +#define AB8500_CODEC_CR102_IT_HSOFFST 7 +#define AB8500_CODEC_CR102_IT_FIFOFULL 6 +#define AB8500_CODEC_CR102_IT_FIFOEMPTY 5 +#define AB8500_CODEC_CR102_IT_DASAT 4 +#define AB8500_CODEC_CR102_IT_ADSAT 3 +#define AB8500_CODEC_CR102_IT_ADDSP 2 +#define AB8500_CODEC_CR102_IT_DADSP 1 +#define AB8500_CODEC_CR102_IT_FIRSID 0 + +/* CR103-CR0x0067 */ +#define AB8500_CODEC_CR103_VSSREADYMASK 7 +#define AB8500_CODEC_CR103_SHORTHSLMASK 2 +#define AB8500_CODEC_CR103_SHORTHSRMASK 1 +#define AB8500_CODEC_CR103_SHORTEARMASK 0 + +/* CR104-CR0x0068 */ +#define AB8500_CODEC_CR104_IT_VSSREADY 7 +#define AB8500_CODEC_CR104_IT_SHORTHSL 2 +#define AB8500_CODEC_CR104_IT_SHORTHSR 1 +#define AB8500_CODEC_CR104_IT_SHORTEAR 0 + +/* CR105-CR0x0069 */ +#define AB8500_CODEC_CR105_BFIFOMASK 7 +#define AB8500_CODEC_CR105_BFIFOINT 0 + +/* CR106-CR0x006A */ +#define AB8500_CODEC_CR106_BFIFOTX 0 + +/* CR107-CR0x006B */ +#define AB8500_CODEC_CR107_BFIFOEXSL 5 +#define AB8500_CODEC_CR107_PREBITCLK0 2 +#define AB8500_CODEC_CR107_BFIFOMAST 1 +#define AB8500_CODEC_CR107_BFIFORUN 0 + +/* CR108-CR0x006C */ +#define AB8500_CODEC_CR108_BFIFOFRAMESW 0 + +/* CR109-CR0x006D */ +#define AB8500_CODEC_CR109_BFIFOWAKEUP 0 + +/* CR110-CR0x006E */ +#define AB8500_CODEC_CR110_BFIFOSAMPLE 0 + +/* CR111-CR0x006F */ +#define AB8500_CODEC_CR111_AUD_IP_REV 0 + +/* For SetVolume API*/ +#define AB8500_CODEC_MAX_VOLUME 100 + +/* Analog MIC1 & MIC2 */ +#define AB8500_CODEC_MIC_VOLUME_MAX 31 +#define AB8500_CODEC_MIC_VOLUME_MEDIUM 15 +#define AB8500_CODEC_MIC_VOLUME_MIN 0 + +/* Line-in */ +#define AB8500_CODEC_LINEIN_VOLUME_MAX 15 +#define AB8500_CODEC_LINEIN_VOLUME_MEDIUM 7 +#define AB8500_CODEC_LINEIN_VOLUME_MIN 0 + +/* HeadSet */ +#define AB8500_CODEC_HEADSET_VOLUME_MAX 13 +#define AB8500_CODEC_HEADSET_VOLUME_MEDIUM 6 +#define AB8500_CODEC_HEADSET_VOLUME_MIN 0 + +/* HeadSet Digital */ +#define AB8500_CODEC_HEADSET_D_VOLUME_MAX 0 +#define AB8500_CODEC_HEADSET_D_VOLUME_MEDIUM 7 +#define AB8500_CODEC_HEADSET_D_VOLUME_MIN 15 +#define AB8500_CODEC_HEADSET_D_VOLUME_0DB 8 + +/* Digital AD Path */ +#define AB8500_CODEC_AD_D_VOLUME_MAX 0 +#define AB8500_CODEC_AD_D_VOLUME_MEDIUM 31 +#define AB8500_CODEC_AD_D_VOLUME_MIN 63 + +/* Digital DA Path */ +#define AB8500_CODEC_DA_D_VOLUME_MAX 0 +#define AB8500_CODEC_DA_D_VOLUME_MEDIUM 31 +#define AB8500_CODEC_DA_D_VOLUME_MIN 63 + +/* EarPiece Digital */ +#define AB8500_CODEC_EARPIECE_D_VOLUME_MAX 0 +#define AB8500_CODEC_EARPIECE_D_VOLUME_MEDIUM 7 +#define AB8500_CODEC_EARPIECE_D_VOLUME_MIN 15 + +/* AD1 loopback to HFL & HFR Digital */ +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MAX 0 +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MEDIUM 31 +#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MIN 63 + +/* Line-in to HSL & HSR */ +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX 0 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MEDIUM 9 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN 18 +#define AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN 19 + +/* Vibrator */ +#define AB8500_CODEC_VIBRATOR_VOLUME_MAX 100 +#define AB8500_CODEC_VIBRATOR_VOLUME_MEDIUM 50 +#define AB8500_CODEC_VIBRATOR_VOLUME_MIN 0 + +/* CR0 - 7 */ +typedef enum { + AB8500_CODEC_CR0_POWERUP_OFF, + AB8500_CODEC_CR0_POWERUP_ON +} t_ab8500_codec_cr0_powerup; + +/* CR0 - 3 */ +typedef enum { + AB8500_CODEC_CR0_ENAANA_OFF, + AB8500_CODEC_CR0_ENAANA_ON +} t_ab8500_codec_cr0_enaana; + +/* CR1 - 7 */ +typedef enum { + AB8500_CODEC_CR1_SWRESET_DISABLED, + AB8500_CODEC_CR1_SWRESET_ENABLED +} t_ab8500_codec_cr1_swreset; + +/* CR2 - 7 */ +typedef enum { + AB8500_CODEC_CR2_ENAD1_DISABLED, + AB8500_CODEC_CR2_ENAD1_ENABLED +} t_ab8500_codec_cr2_enad1; + +/* CR2 - 6 */ +typedef enum { + AB8500_CODEC_CR2_ENAD2_DISABLED, + AB8500_CODEC_CR2_ENAD2_ENABLED +} t_ab8500_codec_cr2_enad2; + +/* CR2 - 5 */ +typedef enum { + AB8500_CODEC_CR2_ENAD3_DISABLED, + AB8500_CODEC_CR2_ENAD3_ENABLED +} t_ab8500_codec_cr2_enad3; + +/* CR2 - 4 */ +typedef enum { + AB8500_CODEC_CR2_ENAD4_DISABLED, + AB8500_CODEC_CR2_ENAD4_ENABLED +} t_ab8500_codec_cr2_enad4; + +/* CR2 - 3 */ +typedef enum { + AB8500_CODEC_CR2_ENAD5_DISABLED, + AB8500_CODEC_CR2_ENAD5_ENABLED +} t_ab8500_codec_cr2_enad5; + +/* CR2 - 2 */ +typedef enum { + AB8500_CODEC_CR2_ENAD6_DISABLED, + AB8500_CODEC_CR2_ENAD6_ENABLED +} t_ab8500_codec_cr2_enad6; + +/* CR3 - 7 */ +typedef enum { + AB8500_CODEC_CR3_ENDA1_DISABLED, + AB8500_CODEC_CR3_ENDA1_ENABLED +} t_ab8500_codec_cr3_enda1; + +/* CR3 - 6 */ +typedef enum { + AB8500_CODEC_CR3_ENDA2_DISABLED, + AB8500_CODEC_CR3_ENDA2_ENABLED +} t_ab8500_codec_cr3_enda2; + +/* CR3 - 5 */ +typedef enum { + AB8500_CODEC_CR3_ENDA3_DISABLED, + AB8500_CODEC_CR3_ENDA3_ENABLED +} t_ab8500_codec_cr3_enda3; + +/* CR3 - 4 */ +typedef enum { + AB8500_CODEC_CR3_ENDA4_DISABLED, + AB8500_CODEC_CR3_ENDA4_ENABLED +} t_ab8500_codec_cr3_enda4; + +/* CR3 - 3 */ +typedef enum { + AB8500_CODEC_CR3_ENDA5_DISABLED, + AB8500_CODEC_CR3_ENDA5_ENABLED +} t_ab8500_codec_cr3_enda5; + +/* CR3 - 2 */ +typedef enum { + AB8500_CODEC_CR3_ENDA6_DISABLED, + AB8500_CODEC_CR3_ENDA6_ENABLED +} t_ab8500_codec_cr3_enda6; + +/* CR4 - 7 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWHS_NORMAL, + AB8500_CODEC_CR4_LOWPOWHS_LP +} t_ab8500_codec_cr4_lowpowhs; + +/* CR4 - 6:5 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWDACHS_NORMAL, + AB8500_CODEC_CR4_LOWPOWDACHS_DRIVERS_LP, + AB8500_CODEC_CR4_LOWPOWDACHS_LP, + AB8500_CODEC_CR4_LOWPOWDACHS_BOTH_LP +} t_ab8500_codec_cr4_lowpowdachs; + +/* CR4 - 4 */ +typedef enum { + AB8500_CODEC_CR4_LOWPOWEAR_NORMAL, + AB8500_CODEC_CR4_LOWPOWEAR_LP +} t_ab8500_codec_cr4_lowpowear; + +/* CR4 - 3:2 */ +typedef enum { + AB8500_CODEC_CR4_EAR_SEL_CM_0_95V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_1V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_27V, + AB8500_CODEC_CR4_EAR_SEL_CM_1_58V +} t_ab8500_codec_cr4_ear_sel_cm; + +/* CR4 - 1 */ +typedef enum { + AB8500_CODEC_CR4_HS_HP_EN_FILTER_DISABLED, + AB8500_CODEC_CR4_HS_HP_EN_FILTER_ENABLED +} t_ab8500_codec_cr4_hs_hp_en; + +/* CR5 - 7 */ +typedef enum { + AB8500_CODEC_CR5_ENMIC1_DISABLED, + AB8500_CODEC_CR5_ENMIC1_ENABLED +} t_ab8500_codec_cr5_enmic1; + +/* CR5 - 6 */ +typedef enum { + AB8500_CODEC_CR5_ENMIC2_DISABLED, + AB8500_CODEC_CR5_ENMIC2_ENABLED +} t_ab8500_codec_cr5_enmic2; + +/* CR5 - 5 */ +typedef enum { + AB8500_CODEC_CR5_ENLINL_DISABLED, + AB8500_CODEC_CR5_ENLINL_ENABLED +} t_ab8500_codec_cr5_enlinl; + +/* CR5 - 4 */ +typedef enum { + AB8500_CODEC_CR5_ENLINR_DISABLED, + AB8500_CODEC_CR5_ENLINR_ENABLED +} t_ab8500_codec_cr5_enlinr; + +/* CR5 - 3 */ +typedef enum { + AB8500_CODEC_CR5_MUTMIC1_DISABLED, + AB8500_CODEC_CR5_MUTMIC1_ENABLED +} t_ab8500_codec_cr5_mutmic1; + +/* CR5 - 2 */ +typedef enum { + AB8500_CODEC_CR5_MUTMIC2_DISABLED, + AB8500_CODEC_CR5_MUTMIC2_ENABLED +} t_ab8500_codec_cr5_mutmic2; + +/* CR5 - 1 */ +typedef enum { + AB8500_CODEC_CR5_MUTLINL_DISABLED, + AB8500_CODEC_CR5_MUTLINL_ENABLED +} t_ab8500_codec_cr5_mutlinl; + +/* CR5 - 0 */ +typedef enum { + AB8500_CODEC_CR5_MUTLINR_DISABLED, + AB8500_CODEC_CR5_MUTLINR_ENABLED +} t_ab8500_codec_cr5_mutlinr; + +/* CR6 - 7 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC1_DISABLED, + AB8500_CODEC_CR6_ENDMIC1_ENABLED +} t_ab8500_codec_cr6_endmic1; + +/* CR6 - 6 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC2_DISABLED, + AB8500_CODEC_CR6_ENDMIC2_ENABLED +} t_ab8500_codec_cr6_endmic2; + +/* CR6 - 5 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC3_DISABLED, + AB8500_CODEC_CR6_ENDMIC3_ENABLED +} t_ab8500_codec_cr6_endmic3; + +/* CR6 - 4 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC4_DISABLED, + AB8500_CODEC_CR6_ENDMIC4_ENABLED +} t_ab8500_codec_cr6_endmic4; + +/* CR6 - 3 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC5_DISABLED, + AB8500_CODEC_CR6_ENDMIC5_ENABLED +} t_ab8500_codec_cr6_endmic5; + +/* CR6 - 2 */ +typedef enum { + AB8500_CODEC_CR6_ENDMIC6_DISABLED, + AB8500_CODEC_CR6_ENDMIC6_ENABLED +} t_ab8500_codec_cr6_endmic6; + +/* CR7 - 7 */ +typedef enum { + AB8500_CODEC_CR7_MIC1SEL_MIC1A, + AB8500_CODEC_CR7_MIC1SEL_MIC1B +} t_ab8500_codec_cr7_mic1sel; + +/* CR7 - 6 */ +typedef enum { + AB8500_CODEC_CR7_LINRSEL_MIC2, + AB8500_CODEC_CR7_LINRSEL_LINR +} t_ab8500_codec_cr7_linrsel; + +/* CR7 - 5 */ +typedef enum { + AB8500_CODEC_CR7_ENDRVHSL_DISABLED, + AB8500_CODEC_CR7_ENDRVHSL_ENABLED +} t_ab8500_codec_cr7_endrvhsl; + +/* CR7 - 4 */ +typedef enum { + AB8500_CODEC_CR7_ENDRVHSR_DISABLED, + AB8500_CODEC_CR7_ENDRVHSR_ENABLED +} t_ab8500_codec_cr7_endrvhsr; + +/* CR7 - 2 */ +typedef enum { + AB8500_CODEC_CR7_ENADCMIC_DISABLED, + AB8500_CODEC_CR7_ENADCMIC_ENABLED +} t_ab8500_codec_cr7_enadcmic; + +/* CR7 - 1 */ +typedef enum { + AB8500_CODEC_CR7_ENADCLINL_DISABLED, + AB8500_CODEC_CR7_ENADCLINL_ENABLED +} t_ab8500_codec_cr7_enadclinl; + +/* CR7 - 0 */ +typedef enum { + AB8500_CODEC_CR7_ENADCLINR_DISABLED, + AB8500_CODEC_CR7_ENADCLINR_ENABLED +} t_ab8500_codec_cr7_enadclinr; + +/* CR8 - 7 */ +typedef enum { + AB8500_CODEC_CR8_CP_DIS_PLDWN_ENABLED, + AB8500_CODEC_CR8_CP_DIS_PLDWN_DISABLED +} t_ab8500_codec_cr8_cp_dis_pldwn; + +/* CR8 - 6 */ +typedef enum { + AB8500_CODEC_CR8_ENEAR_DISABLED, + AB8500_CODEC_CR8_ENEAR_ENABLED +} t_ab8500_codec_cr8_enear; + +/* CR8 - 5 */ +typedef enum { + AB8500_CODEC_CR8_ENHSL_DISABLED, + AB8500_CODEC_CR8_ENHSL_ENABLED +} t_ab8500_codec_cr8_enhsl; + +/* CR8 - 4 */ +typedef enum { + AB8500_CODEC_CR8_ENHSR_DISABLED, + AB8500_CODEC_CR8_ENHSR_ENABLED +} t_ab8500_codec_cr8_enhsr; + +/* CR8 - 3 */ +typedef enum { + AB8500_CODEC_CR8_ENHFL_DISABLED, + AB8500_CODEC_CR8_ENHFL_ENABLED +} t_ab8500_codec_cr8_enhfl; + +/* CR8 - 2 */ +typedef enum { + AB8500_CODEC_CR8_ENHFR_DISABLED, + AB8500_CODEC_CR8_ENHFR_ENABLED +} t_ab8500_codec_cr8_enhfr; + +/* CR8 - 1 */ +typedef enum { + AB8500_CODEC_CR8_ENVIBL_DISABLED, + AB8500_CODEC_CR8_ENVIBL_ENABLED +} t_ab8500_codec_cr8_envibl; + +/* CR8 - 0 */ +typedef enum { + AB8500_CODEC_CR8_ENVIBR_DISABLED, + AB8500_CODEC_CR8_ENVIBR_ENABLED +} t_ab8500_codec_cr8_envibr; + +/* CR9 - 6 */ +typedef enum { + AB8500_CODEC_CR9_ENDACEAR_DISABLED, + AB8500_CODEC_CR9_ENDACEAR_ENABLED +} t_ab8500_codec_cr9_endacear; + +/* CR9 - 5 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHSL_DISABLED, + AB8500_CODEC_CR9_ENDACHSL_ENABLED +} t_ab8500_codec_cr9_endachsl; + +/* CR9 - 4 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHSR_DISABLED, + AB8500_CODEC_CR9_ENDACHSR_ENABLED +} t_ab8500_codec_cr9_endachsr; + +/* CR9 - 3 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHFL_DISABLED, + AB8500_CODEC_CR9_ENDACHFL_ENABLED +} t_ab8500_codec_cr9_endachfl; + +/* CR9 - 2 */ +typedef enum { + AB8500_CODEC_CR9_ENDACHFR_DISABLED, + AB8500_CODEC_CR9_ENDACHFR_ENABLED +} t_ab8500_codec_cr9_endachfr; + +/* CR9 - 1 */ +typedef enum { + AB8500_CODEC_CR9_ENDACVIBL_DISABLED, + AB8500_CODEC_CR9_ENDACVIBL_ENABLED +} t_ab8500_codec_cr9_endacvibl; + +/* CR9 - 0 */ +typedef enum { + AB8500_CODEC_CR9_ENDACVIBR_DISABLED, + AB8500_CODEC_CR9_ENDACVIBR_ENABLED +} t_ab8500_codec_cr9_endacvibr; + +/* CR10 - 6 */ +typedef enum { + AB8500_CODEC_CR10_MUTEEAR_DISABLED, + AB8500_CODEC_CR10_MUTEEAR_ENABLED +} t_ab8500_codec_cr10_muteear; + +/* CR10 - 5 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHSL_DISABLED, + AB8500_CODEC_CR10_MUTEHSL_ENABLED +} t_ab8500_codec_cr10_mutehsl; + +/* CR10 - 4 */ +typedef enum { + AB8500_CODEC_CR10_MUTEHSR_DISABLED, + AB8500_CODEC_CR10_MUTEHSR_ENABLED +} t_ab8500_codec_cr10_mutehsr; + +/* CR11 - 7 */ +typedef enum { + AB8500_CODEC_CR11_ENSHORTPWD_DISABLED, + AB8500_CODEC_CR11_ENSHORTPWD_ENABLED +} t_ab8500_codec_cr11_enshortpwd; + +/* CR11 - 6 */ +typedef enum { + AB8500_CODEC_CR11_EARSHORTDIS_ENABLED, + AB8500_CODEC_CR11_EARSHORTDIS_DISABLED +} t_ab8500_codec_cr11_earshortdis; + +/* CR11 - 5 */ +typedef enum { + AB8500_CODEC_CR11_HSSHORTDIS_ENABLED, + AB8500_CODEC_CR11_HSSHORTDIS_DISABLED +} t_ab8500_codec_cr11_hsshortdis; + +/* CR11 - 4 */ +typedef enum { + AB8500_CODEC_CR11_HSPULLDEN_HIGH, + AB8500_CODEC_CR11_HSPULLDEN_DOWN +} t_ab8500_codec_cr11_hspullden; + +/* CR11 - 2 */ +typedef enum { + AB8500_CODEC_CR11_HSOSCEN_SYSTEMCLOCK, + AB8500_CODEC_CR11_HSOSCEN_LOCALOSC +} t_ab8500_codec_cr11_hsoscen; + +/* CR11 - 1 */ +typedef enum { + AB8500_CODEC_CR11_HSFADEN_FADING, + AB8500_CODEC_CR11_HSFADEN_IMMEDIATELY +} t_ab8500_codec_cr11_hsfaden; + +/* CR11 - 0 */ +typedef enum { + AB8500_CODEC_CR11_HSZCDDIS_ONZEROCROSS, + AB8500_CODEC_CR11_HSZCDDIS_WITHOUTZEROCROSS +} t_ab8500_codec_cr11_hszcddis; + +/* CR12 - 7 */ +typedef enum { + AB8500_CODEC_CR12_ENCPHS_DISABLED, + AB8500_CODEC_CR12_ENCPHS_ENABLED +} t_ab8500_codec_cr12_encphs; + +/* CR12 - 0 */ +typedef enum { + AB8500_CODEC_CR12_HSAUTOEN_DISABLED, + AB8500_CODEC_CR12_HSAUTOEN_ENABLED +} t_ab8500_codec_cr12_hsautoen; + +/* CR13 - 7:4 */ +typedef enum { + AB8500_CODEC_CR13_ENVDET_HTHRESH_25, + AB8500_CODEC_CR13_ENVDET_HTHRESH_50, + AB8500_CODEC_CR13_ENVDET_HTHRESH_100, + AB8500_CODEC_CR13_ENVDET_HTHRESH_150, + AB8500_CODEC_CR13_ENVDET_HTHRESH_200, + AB8500_CODEC_CR13_ENVDET_HTHRESH_250, + AB8500_CODEC_CR13_ENVDET_HTHRESH_300, + AB8500_CODEC_CR13_ENVDET_HTHRESH_350, + AB8500_CODEC_CR13_ENVDET_HTHRESH_400, + AB8500_CODEC_CR13_ENVDET_HTHRESH_450, + AB8500_CODEC_CR13_ENVDET_HTHRESH_500, + AB8500_CODEC_CR13_ENVDET_HTHRESH_550, + AB8500_CODEC_CR13_ENVDET_HTHRESH_600, + AB8500_CODEC_CR13_ENVDET_HTHRESH_650, + AB8500_CODEC_CR13_ENVDET_HTHRESH_700, + AB8500_CODEC_CR13_ENVDET_HTHRESH_750 +} t_ab8500_codec_cr13_envdet_hthresh; + +/* CR13 - 3:0 */ +typedef enum { + AB8500_CODEC_CR13_ENVDET_LTHRESH_25, + AB8500_CODEC_CR13_ENVDET_LTHRESH_50, + AB8500_CODEC_CR13_ENVDET_LTHRESH_100, + AB8500_CODEC_CR13_ENVDET_LTHRESH_150, + AB8500_CODEC_CR13_ENVDET_LTHRESH_200, + AB8500_CODEC_CR13_ENVDET_LTHRESH_250, + AB8500_CODEC_CR13_ENVDET_LTHRESH_300, + AB8500_CODEC_CR13_ENVDET_LTHRESH_350, + AB8500_CODEC_CR13_ENVDET_LTHRESH_400, + AB8500_CODEC_CR13_ENVDET_LTHRESH_450, + AB8500_CODEC_CR13_ENVDET_LTHRESH_500, + AB8500_CODEC_CR13_ENVDET_LTHRESH_550, + AB8500_CODEC_CR13_ENVDET_LTHRESH_600, + AB8500_CODEC_CR13_ENVDET_LTHRESH_650, + AB8500_CODEC_CR13_ENVDET_LTHRESH_700, + AB8500_CODEC_CR13_ENVDET_LTHRESH_750 +} t_ab8500_codec_cr13_envdet_lthresh; + +/* CR14 - 7 */ +typedef enum { + AB8500_CODEC_CR14_SMPSLVEN_HIGHVOLTAGE, + AB8500_CODEC_CR14_SMPSLVEN_LOWVOLTAGE +} t_ab8500_codec_cr14_smpslven; + +/* CR14 - 6 */ +typedef enum { + AB8500_CODEC_CR14_ENVDETSMPSEN_DISABLED, + AB8500_CODEC_CR14_ENVDETSMPSEN_ENABLED +} t_ab8500_codec_cr14_envdetsmpsen; + +/* CR14 - 5 */ +typedef enum { + AB8500_CODEC_CR14_CPLVEN_HIGHVOLTAGE, + AB8500_CODEC_CR14_CPLVEN_LOWVOLTAGE +} t_ab8500_codec_cr14_cplven; + +/* CR14 - 4 */ +typedef enum { + AB8500_CODEC_CR14_ENVDETCPEN_DISABLED, + AB8500_CODEC_CR14_ENVDETCPEN_ENABLED +} t_ab8500_codec_cr14_envdetcpen; + +/* CR14 - 3:0 */ +typedef enum { + AB8500_CODEC_CR14_ENVET_TIME_27USEC, + AB8500_CODEC_CR14_ENVET_TIME_53USEC, + AB8500_CODEC_CR14_ENVET_TIME_106USEC, + AB8500_CODEC_CR14_ENVET_TIME_212USEC, + AB8500_CODEC_CR14_ENVET_TIME_424USEC, + AB8500_CODEC_CR14_ENVET_TIME_848USEC, + AB8500_CODEC_CR14_ENVET_TIME_1MSEC, + AB8500_CODEC_CR14_ENVET_TIME_3MSEC, + AB8500_CODEC_CR14_ENVET_TIME_6MSEC, + AB8500_CODEC_CR14_ENVET_TIME_13MSEC, + AB8500_CODEC_CR14_ENVET_TIME_27MSEC, + AB8500_CODEC_CR14_ENVET_TIME_54MSEC, + AB8500_CODEC_CR14_ENVET_TIME_109MSEC, + AB8500_CODEC_CR14_ENVET_TIME_218MSEC, + AB8500_CODEC_CR14_ENVET_TIME_436MSEC, + AB8500_CODEC_CR14_ENVET_TIME_872MSEC, +} t_ab8500_codec_cr14_envet_time; + +/* CR15 - 7 */ +typedef enum { + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH, + AB8500_CODEC_CR15_PWMTOVIBL_PWM +} t_ab8500_codec_cr15_pwmtovibl; + +/* CR15 - 6 */ +typedef enum { + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH, + AB8500_CODEC_CR15_PWMTOVIBR_PWM +} t_ab8500_codec_cr15_pwmtovibr; + +/* CR15 - 5 */ +typedef enum { + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL, + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE +} t_ab8500_codec_cr15_pwmlctrl; + +/* CR15 - 4 */ +typedef enum { + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL, + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE +} t_ab8500_codec_cr15_pwmrctrl; + +/* CR15 - 3 */ +typedef enum { + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL, + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE +} t_ab8500_codec_cr15_pwmnlctrl; + +/* CR15 - 2 */ +typedef enum { + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL, + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE +} t_ab8500_codec_cr15_pwmplctrl; + +/* CR15 - 1 */ +typedef enum { + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL, + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE +} t_ab8500_codec_cr15_pwmnrctrl; + +/* CR15 - 0 */ +typedef enum { + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL, + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE +} t_ab8500_codec_cr15_pwmprctrl; + +/* CR16 - 7 */ +typedef enum { + AB8500_CODEC_CR16_PWMNLPOL_GNDVIB, + AB8500_CODEC_CR16_PWMNLPOL_VINVIB +} t_ab8500_codec_cr16_pwmnlpol; + +/* CR16 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr16_pwmnldutycycle; + +/* CR17 - 7 */ +typedef enum { + AB8500_CODEC_CR17_PWMPLPOL_GNDVIB, + AB8500_CODEC_CR17_PWMPLPOL_VINVIB +} t_ab8500_codec_cr17_pwmplpol; + +/* CR17 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr17_pwmpldutycycle; + +/* CR18 - 7 */ +typedef enum { + AB8500_CODEC_CR18_PWMNRPOL_GNDVIB, + AB8500_CODEC_CR18_PWMNRPOL_VINVIB +} t_ab8500_codec_cr18_pwmnrpol; + +/* CR18 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr18_pwmnrdutycycle; + +/* CR19 - 7 */ +typedef enum { + AB8500_CODEC_CR19_PWMPRPOL_GNDVIB, + AB8500_CODEC_CR19_PWMPRPOL_VINVIB +} t_ab8500_codec_cr19_pwmprpol; + +/* CR19 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr19_pwmprdutycycle; + +/* CR20 - 7 */ +typedef enum { + AB8500_CODEC_CR20_EN_SE_MIC1_DIFFERENTIAL, + AB8500_CODEC_CR20_EN_SE_MIC1_SINGLE +} t_ab8500_codec_cr20_en_se_mic1; + +/* CR20 - 6 */ +typedef enum { + AB8500_CODEC_CR20_LOW_POW_MIC1_NORMAL, + AB8500_CODEC_CR20_LOW_POW_MIC1_LOW_POWER +} t_ab8500_codec_cr20_low_pow_mic1; + +/* CR20 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr20_mic1_gain; + +/* CR21 - 7 */ +typedef enum { + AB8500_CODEC_CR21_EN_SE_MIC2_DIFFERENTIAL, + AB8500_CODEC_CR21_EN_SE_MIC2_SINGLE +} t_ab8500_codec_cr21_en_se_mic2; + +/* CR21 - 6 */ +typedef enum { + AB8500_CODEC_CR21_LOW_POW_MIC2_NORMAL, + AB8500_CODEC_CR21_LOW_POW_MIC2_LOW_POWER +} t_ab8500_codec_cr21_low_pow_mic2; + +/* CR21 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr21_mic2_gain; + +/* CR22 - 7:4 */ +typedef t_uint8 t_ab8500_codec_cr22_hsl_gain; + +/* CR22 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr22_hsr_gain; + +/* CR23 - 7:4 */ +typedef t_uint8 t_ab8500_codec_cr23_linl_gain; + +/* CR23 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr23_linr_gain; + +/* CR24 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr24_lintohsl_gain; + +/* CR25 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr25_lintohsr_gain; + +/* CR26 - 7 */ +typedef enum { + AB8500_CODEC_CR26_AD1NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD1NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad1nh; + +/* CR26 - 6 */ +typedef enum { + AB8500_CODEC_CR26_AD2NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD2NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad2nh; + +/* CR26 - 5 */ +typedef enum { + AB8500_CODEC_CR26_AD3NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD3NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad3nh; + +/* CR26 - 4 */ +typedef enum { + AB8500_CODEC_CR26_AD4NH_FILTER_ENABLED, + AB8500_CODEC_CR26_AD4NH_FILTER_DISABLED +} t_ab8500_codec_cr26_ad4nh; + +/* CR26 - 3 */ +typedef enum { + AB8500_CODEC_CR26_AD1_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad1_voice; + +/* CR26 - 2 */ +typedef enum { + AB8500_CODEC_CR26_AD2_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad2_voice; + +/* CR26 - 1 */ +typedef enum { + AB8500_CODEC_CR26_AD3_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad3_voice; + +/* CR26 - 0 */ +typedef enum { + AB8500_CODEC_CR26_AD4_VOICE_AUDIOFILTER, + AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr26_ad4_voice; + +/* CR27 - 7 */ +typedef enum { + AB8500_CODEC_CR27_EN_MASTGEN_DISABLED, + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED +} t_ab8500_codec_cr27_en_mastgen; + +/* CR27 - 6:5 */ +/* In ab8500_codec.h */ + +/* CR27 - 4 */ +typedef enum { + AB8500_CODEC_CR27_ENFS_BITCLK1_DISABLED, + AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED +} t_ab8500_codec_cr27_enfs_bitclk1; + +/* CR27 - 2:1 */ +/* In ab8500_codec.h */ + +/* CR27 - 0 */ +typedef enum { + AB8500_CODEC_CR27_ENFS_BITCLK0_DISABLED, + AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED +} t_ab8500_codec_cr27_enfs_bitclk0; + +/* CR28 - 6 */ +typedef enum { + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE, + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE +} t_ab8500_codec_cr28_fsync0p; + +/* CR28 - 5 */ +typedef enum { + AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE, + AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE +} t_ab8500_codec_cr28_bitclk0p; + +/* CR28 - 4 */ +typedef enum { + AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED, + AB8500_CODEC_CR28_IF0DEL_DELAYED +} t_ab8500_codec_cr28_if0del; + +/* CR28 - 3:2 */ +typedef enum { + AB8500_CODEC_CR28_IF0FORMAT_DISABLED, + AB8500_CODEC_CR28_IF0FORMAT_TDM, + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED +} t_ab8500_codec_cr28_if0format; + +/* CR28 - 1:0 */ +/* In ab8500_codec.h */ + +/* CR29 - 7 */ +typedef enum { + AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT, + AB8500_CODEC_CR29_IF0DATOIF1AD_SENT +} t_ab8500_codec_cr29_if0datoif1ad; + +/* CR29 - 6 */ +typedef enum { + AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT, + AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT +} t_ab8500_codec_cr29_if0cktoif1ck; + +/* CR29 - 5 */ +typedef enum { + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT, + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT +} t_ab8500_codec_cr29_if1master; + +/* CR29 - 3 */ +typedef enum { + AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT, + AB8500_CODEC_CR29_IF1DATOIF0AD_SENT +} t_ab8500_codec_cr29_if1datoif0ad; + +/* CR29 - 2 */ +typedef enum { + AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT, + AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT +} t_ab8500_codec_cr29_if1cktoif0ck; + +/* CR29 - 1 */ +typedef enum { + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT, + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT +} t_ab8500_codec_cr29_if0master; + +/* CR29 - 0 */ +typedef enum { + AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE, + AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE +} t_ab8500_codec_cr29_if0bfifoen; + +/* CR30 - 6 */ +typedef enum { + AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE, + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE +} t_ab8500_codec_cr30_fsync1p; + +/* CR30 - 5 */ +typedef enum { + AB8500_CODEC_CR30_BITCLK1P_RISING_EDGE, + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE +} t_ab8500_codec_cr30_bitclk1p; + +/* CR30 - 4 */ +typedef enum { + AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED, + AB8500_CODEC_CR30_IF1DEL_DELAYED +} t_ab8500_codec_cr30_if1del; + +/* CR30 - 3:2 */ +typedef enum { + AB8500_CODEC_CR30_IF1FORMAT_DISABLED, + AB8500_CODEC_CR30_IF1FORMAT_TDM, + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED +} t_ab8500_codec_cr30_if1format; + +/* CR30 - 1:0 */ +/* In ab8500_codec.h */ + +/* CR31:46 - 7:4 or 3:0 */ +/* In ab8500_codec.h */ + +/* CR47:50 - 7/6/5/4/3/2/1/0 */ +typedef enum { + AB8500_CODEC_CR47_TO_CR50_HIZ_SL_LOW_IMPEDANCE, + AB8500_CODEC_CR47_TO_CR50_HIZ_SL_HIGH_IMPEDANCE, +} t_ab8500_codec_cr47_to_cr50_hiz_sl; + +/* CR51 - 7 */ +typedef enum { + AB8500_CODEC_CR51_DA12_VOICE_AUDIOFILTER, + AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr51_da12_voice; + +/* CR51 - 6 */ +typedef enum { + AB8500_CODEC_CR51_SWAPDA12_34_NORMAL, + AB8500_CODEC_CR51_SWAPDA12_34_SWAPPED +} t_ab8500_codec_cr51_swapda12_34; + +/* CR51 - 5 */ +typedef enum { + AB8500_CODEC_CR51_SLDAI7TOSLADO1_NOT_LOOPEDBACK, + AB8500_CODEC_CR51_SLDAI7TOSLADO1_LOOPEDBACK +} t_ab8500_codec_cr51_sldai7toslado1; + +/* CR51:58 - 4:0 */ +/* In ab8500_codec.h */ + +/* CR52 - 5 */ +typedef enum { + AB8500_CODEC_CR52_SLDAI8TOSLADO2_NOT_LOOPEDBACK, + AB8500_CODEC_CR52_SLDAI8TOSLADO2_LOOPEDBACK +} t_ab8500_codec_cr52_sldai8toslado2; + +/* CR53 - 7 */ +typedef enum { + AB8500_CODEC_CR53_DA34_VOICE_AUDIOFILTER, + AB8500_CODEC_CR53_DA34_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr53_da34_voice; + +/* CR53 - 5 */ +typedef enum { + AB8500_CODEC_CR53_SLDAI7TOSLADO3_NOT_LOOPEDBACK, + AB8500_CODEC_CR53_SLDAI7TOSLADO3_LOOPEDBACK +} t_ab8500_codec_cr53_sldai7toslado3; + +/* CR54 - 5 */ +typedef enum { + AB8500_CODEC_CR54_SLDAI8TOSLADO4_NOT_LOOPEDBACK, + AB8500_CODEC_CR54_SLDAI8TOSLADO4_LOOPEDBACK +} t_ab8500_codec_cr54_sldai8toslado4; + +/* CR55 - 7 */ +typedef enum { + AB8500_CODEC_CR55_DA56_VOICE_AUDIOFILTER, + AB8500_CODEC_CR55_DA56_VOICE_LOWLATENCYFILTER +} t_ab8500_codec_cr55_da56_voice; + +/* CR55 - 5 */ +typedef enum { + AB8500_CODEC_CR55_SLDAI7TOSLADO5_NOT_LOOPEDBACK, + AB8500_CODEC_CR55_SLDAI7TOSLADO5_LOOPEDBACK +} t_ab8500_codec_cr55_sldai7toslado5; + +/* CR56 - 5 */ +typedef enum { + AB8500_CODEC_CR56_SLDAI8TOSLADO6_NOT_LOOPEDBACK, + AB8500_CODEC_CR56_SLDAI8TOSLADO6_LOOPEDBACK +} t_ab8500_codec_cr56_sldai8toslado6; + +/* CR57 - 5 */ +typedef enum { + AB8500_CODEC_CR57_SLDAI8TOSLADO7_NOT_LOOPEDBACK, + AB8500_CODEC_CR57_SLDAI8TOSLADO7_LOOPEDBACK +} t_ab8500_codec_cr57_sldai8toslado7; + +/* CR58 - 5 */ +typedef enum { + AB8500_CODEC_CR58_SLDAI7TOSLADO8_NOT_LOOPEDBACK, + AB8500_CODEC_CR58_SLDAI7TOSLADO8_LOOPEDBACK +} t_ab8500_codec_cr58_sldai7toslado8; + +/* CR59 - 7 */ +typedef enum { + AB8500_CODEC_CR59_PARLHF_INDEPENDENT, + AB8500_CODEC_CR59_PARLHF_BRIDGED +} t_ab8500_codec_cr59_parlhf; + +/* CR59 - 6 */ +typedef enum { + AB8500_CODEC_CR59_PARLVIB_INDEPENDENT, + AB8500_CODEC_CR59_PARLVIB_BRIDGED +} t_ab8500_codec_cr59_parlvib; + +/* CR59 - 3 */ +typedef enum { + AB8500_CODEC_CR59_CLASSDVIB1_SWAPEN_DISABLED, + AB8500_CODEC_CR59_CLASSDVIB1_SWAPEN_ENABLED +} t_ab8500_codec_cr59_classdvib1_swapen; + +/* CR59 - 2 */ +typedef enum { + AB8500_CODEC_CR59_CLASSDVIB2_SWAPEN_DISABLED, + AB8500_CODEC_CR59_CLASSDVIB2_SWAPEN_ENABLED +} t_ab8500_codec_cr59_classdvib2_swapen; + +/* CR59 - 1 */ +typedef enum { + AB8500_CODEC_CR59_CLASSDHFL_SWAPEN_DISABLED, + AB8500_CODEC_CR59_CLASSDHFL_SWAPEN_ENABLED +} t_ab8500_codec_cr59_classdhfl_swapen; + +/* CR59 - 0 */ +typedef enum { + AB8500_CODEC_CR59_CLASSDHFR_SWAPEN_DISABLED, + AB8500_CODEC_CR59_CLASSDHFR_SWAPEN_ENABLED +} t_ab8500_codec_cr59_classdhfr_swapen; + +/* CR60 - 7:4 */ +typedef enum { + AB8500_CODEC_CR60_CLASSD_FIRBYP_ALL_ENABLED = 0, + AB8500_CODEC_CR60_CLASSD_FIRBYP_LEFT_HF_BYPASSED = 1, + AB8500_CODEC_CR60_CLASSD_FIRBYP_RIGHT_HF_BYPASSED = 2, + AB8500_CODEC_CR60_CLASSD_FIRBYP_VIBRA1_BYPASSED = 4, + AB8500_CODEC_CR60_CLASSD_FIRBYP_VIBRA2_BYPASSED = 8 +} t_ab8500_codec_cr60_classd_firbyp; + +/* CR60 - 3:0 */ +typedef enum { + AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_DISABLED = 0, + AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_LEFT_HF = 1, + AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_RIGHT_HF = 2, + AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_VIBRA1 = 4, + AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_VIBRA2 = 8 +} t_ab8500_codec_cr60_classd_highvolen; + +/* CR61 - 7:4 */ +typedef t_uint8 t_ab8500_codec_cr61_classddith_hpgain; + +/* CR61 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr61_classddith_wgain; + +/* CR62 - Read Only */ +/* CR62 - 5 */ +typedef enum { + AB8500_CODEC_CR62_DMIC1SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC1SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic1sinc3; + +/* CR62 - 4 */ +typedef enum { + AB8500_CODEC_CR62_DMIC2SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC2SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic2sinc3; + +/* CR62 - 3 */ +typedef enum { + AB8500_CODEC_CR62_DMIC3SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC3SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic3sinc3; + +/* CR62 - 2 */ +typedef enum { + AB8500_CODEC_CR62_DMIC4SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC4SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic4sinc3; + +/* CR62 - 1 */ +typedef enum { + AB8500_CODEC_CR62_DMIC5SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC5SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic5sinc3; + +/* CR62 - 0 */ +typedef enum { + AB8500_CODEC_CR62_DMIC6SINC3_SINC5_SELECTED, + AB8500_CODEC_CR62_DMIC6SINC3_SINC3_SELECTED +} t_ab8500_codec_cr62_dmic6sinc3; + +/* CR63 - 7 */ +typedef enum { + AB8500_CODEC_CR63_DATOHSLEN_DISABLED, + AB8500_CODEC_CR63_DATOHSLEN_ENABLED +} t_ab8500_codec_cr63_datohslen; + +/* CR63 - 6 */ +typedef enum { + AB8500_CODEC_CR63_DATOHSREN_DISABLED, + AB8500_CODEC_CR63_DATOHSREN_ENABLED +} t_ab8500_codec_cr63_datohsren; + +/* CR63 - 5 */ +typedef enum { + AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED, + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED +} t_ab8500_codec_cr63_ad1sel; + +/* CR63 - 4 */ +typedef enum { + AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED, + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED +} t_ab8500_codec_cr63_ad2sel; + +/* CR63 - 3 */ +typedef enum { + AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED, + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED +} t_ab8500_codec_cr63_ad3sel; + +/* CR63 - 2 */ +typedef enum { + AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED, + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED +} t_ab8500_codec_cr63_ad5sel; + +/* CR63 - 1 */ +typedef enum { + AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED, + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED +} t_ab8500_codec_cr63_ad6sel; + +/* CR63 - 0 */ +typedef enum { + AB8500_CODEC_CR63_ANCSEL_NOT_MIXED_IN_EAR, + AB8500_CODEC_CR63_ANCSEL_MIXED_IN_EAR +} t_ab8500_codec_cr63_ancsel; + +/* CR64 - 7 */ +typedef enum { + AB8500_CODEC_CR64_DATOHFREN_NOT_MIXED_TO_HFR, + AB8500_CODEC_CR64_DATOHFREN_MIXED_TO_HFR +} t_ab8500_codec_cr64_datohfren; + +/* CR64 - 6 */ +typedef enum { + AB8500_CODEC_CR64_DATOHFLEN_NOT_MIXED_TO_HFL, + AB8500_CODEC_CR64_DATOHFLEN_MIXED_TO_HFL +} t_ab8500_codec_cr64_datohflen; + +/* CR64 - 5 */ +typedef enum { + AB8500_CODEC_CR64_HFRSEL_DA4_MIXED_TO_HFR, + AB8500_CODEC_CR64_HFRSEL_ANC_MIXED_TO_HFR +} t_ab8500_codec_cr64_hfrsel; + +/* CR64 - 4 */ +typedef enum { + AB8500_CODEC_CR64_HFLSEL_DA3_MIXED_TO_HFL, + AB8500_CODEC_CR64_HFLSEL_ANC_MIXED_TO_HFL +} t_ab8500_codec_cr64_hflsel; + +/* CR64 - 3:2 */ +typedef enum { + AB8500_CODEC_CR64_STFIR1SEL_AD_OUT1_SELECTED, + AB8500_CODEC_CR64_STFIR1SEL_AD_OUT3_SELECTED, + AB8500_CODEC_CR64_STFIR1SEL_DA_IN1_SELECTED +} t_ab8500_codec_cr64_stfir1sel; + +/* CR64 - 1:0 */ +typedef enum { + AB8500_CODEC_CR64_STFIR2SEL_AD_OUT2_SELECTED, + AB8500_CODEC_CR64_STFIR2SEL_AD_OUT4_SELECTED, + AB8500_CODEC_CR64_STFIR2SEL_DA_IN2_SELECTED +} t_ab8500_codec_cr64_stfir2sel; + +/* CR65 - 6 */ +typedef enum { + AB8500_CODEC_CR65_FADEDIS_AD1_ENABLED, + AB8500_CODEC_CR65_FADEDIS_AD1_DISABLED +} t_ab8500_codec_cr65_fadedis_ad1; + +/* CR65 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr65_ad1gain; + +/* CR66 - 6 */ +typedef enum { + AB8500_CODEC_CR66_FADEDIS_AD2_ENABLED, + AB8500_CODEC_CR66_FADEDIS_AD2_DISABLED +} t_ab8500_codec_cr66_fadedis_ad2; + +/* CR66 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr66_ad2gain; + +/* CR67 - 6 */ +typedef enum { + AB8500_CODEC_CR67_FADEDIS_AD3_ENABLED, + AB8500_CODEC_CR67_FADEDIS_AD3_DISABLED +} t_ab8500_codec_cr67_fadedis_ad3; + +/* CR67 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr67_ad3gain; + +/* CR68 - 6 */ +typedef enum { + AB8500_CODEC_CR68_FADEDIS_AD4_ENABLED, + AB8500_CODEC_CR68_FADEDIS_AD4_DISABLED +} t_ab8500_codec_cr68_fadedis_ad4; + +/* CR68 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr68_ad4gain; + +/* CR69 - 6 */ +typedef enum { + AB8500_CODEC_CR69_FADEDIS_AD5_ENABLED, + AB8500_CODEC_CR69_FADEDIS_AD5_DISABLED +} t_ab8500_codec_cr69_fadedis_ad5; + +/* CR69 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr69_ad5gain; + +/* CR70 - 6 */ +typedef enum { + AB8500_CODEC_CR70_FADEDIS_AD6_ENABLED, + AB8500_CODEC_CR70_FADEDIS_AD6_DISABLED +} t_ab8500_codec_cr70_fadedis_ad6; + +/* CR70 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr70_ad6gain; + +/* CR71 - 6 */ +typedef enum { + AB8500_CODEC_CR71_FADEDIS_DA1_ENABLED, + AB8500_CODEC_CR71_FADEDIS_DA1_DISABLED +} t_ab8500_codec_cr71_fadedis_da1; + +/* CR71 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr71_da1gain; + +/* CR72 - 6 */ +typedef enum { + AB8500_CODEC_CR72_FADEDIS_DA2_ENABLED, + AB8500_CODEC_CR72_FADEDIS_DA2_DISABLED +} t_ab8500_codec_cr72_fadedis_da2; + +/* CR72 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr72_da2gain; + +/* CR73 - 6 */ +typedef enum { + AB8500_CODEC_CR73_FADEDIS_DA3_ENABLED, + AB8500_CODEC_CR73_FADEDIS_DA3_DISABLED +} t_ab8500_codec_cr73_fadedis_da3; + +/* CR73 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr73_da3gain; + +/* CR74 - 6 */ +typedef enum { + AB8500_CODEC_CR74_FADEDIS_DA4_ENABLED, + AB8500_CODEC_CR74_FADEDIS_DA4_DISABLED +} t_ab8500_codec_cr74_fadedis_da4; + +/* CR74 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr74_da4gain; + +/* CR75 - 6 */ +typedef enum { + AB8500_CODEC_CR75_FADEDIS_DA5_ENABLED, + AB8500_CODEC_CR75_FADEDIS_DA5_DISABLED +} t_ab8500_codec_cr75_fadedis_da5; + +/* CR75 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr75_da5gain; + +/* CR76 - 6 */ +typedef enum { + AB8500_CODEC_CR76_FADEDIS_DA6_ENABLED, + AB8500_CODEC_CR76_FADEDIS_DA6_DISABLED +} t_ab8500_codec_cr76_fadedis_da6; + +/* CR76 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr76_da6gain; + +/* CR77 - 6 */ +typedef enum { + AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_ENABLED, + AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_DISABLED +} t_ab8500_codec_cr77_fadedis_ad1l; + +/* CR77 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr77_ad1lbgain_to_hfl; + +/* CR78 - 6 */ +typedef enum { + AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_ENABLED, + AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_DISABLED +} t_ab8500_codec_cr78_fadedis_ad2l; + +/* CR78 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr78_ad2lbgain_to_hfr; + +/* CR79 - 7 */ +typedef enum { + AB8500_CODEC_CR79_HSSINC1_SINC3_CHOOSEN, + AB8500_CODEC_CR79_HSSINC1_SINC1_CHOOSEN +} t_ab8500_codec_cr79_hssinc1; + +/* CR79 - 4 */ +typedef enum { + AB8500_CODEC_CR79_FADEDIS_HSL_ENABLED, + AB8500_CODEC_CR79_FADEDIS_HSL_DISABLED +} t_ab8500_codec_cr79_fadedis_hsl; + +/* CR79 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr79_hsldgain; + +/* CR80 - 7:6 */ +typedef enum { + AB8500_CODEC_CR80_FADE_SPEED_1MS, + AB8500_CODEC_CR80_FADE_SPEED_4MS, + AB8500_CODEC_CR80_FADE_SPEED_8MS, + AB8500_CODEC_CR80_FADE_SPEED_16MS, +} t_ab8500_codec_cr80_fade_speed; + +/* CR80 - 4 */ +typedef enum { + AB8500_CODEC_CR80_FADEDIS_HSR_ENABLED, + AB8500_CODEC_CR80_FADEDIS_HSR_DISABLED +} t_ab8500_codec_cr80_fadedis_hsr; + +/* CR80 - 3:0 */ +typedef t_uint8 t_ab8500_codec_cr80_hsrdgain; + +/* CR81 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr81_stfir1gain; + +/* CR82 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr82_stfir2gain; + +/* CR83 - 2 */ +typedef enum { + AB8500_CODEC_CR83_ENANC_DISABLED, + AB8500_CODEC_CR83_ENANC_ENABLED +} t_ab8500_codec_cr83_enanc; + +/* CR83 - 1 */ +typedef enum { + AB8500_CODEC_CR83_ANCIIRINIT_NOT_STARTED, + AB8500_CODEC_CR83_ANCIIRINIT_STARTED +} t_ab8500_codec_cr83_anciirinit; + +/* CR83 - 0 */ +typedef enum { + AB8500_CODEC_CR83_ANCFIRUPDATE_RESETTED, + AB8500_CODEC_CR83_ANCFIRUPDATE_NOT_RESETTED +} t_ab8500_codec_cr83_ancfirupdate; + +/* CR84 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr84_ancinshift; + +/* CR85 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr85_ancfiroutshift; + +/* CR86 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr86_ancshiftout; + +/* CR87 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr87_ancfircoeff_msb; + +/* CR88 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr88_ancfircoeff_lsb; + +/* CR89 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr89_anciircoeff_msb; + +/* CR90 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr90_anciircoeff_lsb; + +/* CR91 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr91_ancwarpdel_msb; + +/* CR92 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr92_ancwarpdel_lsb; + +/* CR93 - Read Only */ +/* CR93 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr93_ancfirpeak_msb; + +/* CR94 - Read Only */ +/* CR94 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr94_ancfirpeak_lsb; + +/* CR95 - Read Only */ +/* CR95 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr95_anciirpeak_msb; + +/* CR96 - Read Only */ +/* CR96 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr96_anciirpeak_lsb; + +/* CR97 - 7 */ +typedef enum { + AB8500_CODEC_CR97_STFIR_SET_LAST_NOT_APPLIED, + AB8500_CODEC_CR97_STFIR_SET_LAST_APPLIED +} t_ab8500_codec_cr97_stfir_set; + +/* CR97 - 6:0 */ +typedef t_uint8 t_ab8500_codec_cr97_stfir_addr; + +/* CR98 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr98_stfir_coeff_msb; + +/* CR99 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr99_stfir_coeff_lsb; + +/* CR100 - 2 */ +typedef enum { + AB8500_CODEC_CR100_ENSTFIRS_DISABLED, + AB8500_CODEC_CR100_ENSTFIRS_ENABLED +} t_ab8500_codec_cr100_enstfirs; + +/* CR100 - 1 */ +typedef enum { + AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF0_DATA_RATE, + AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF1_DATA_RATE +} t_ab8500_codec_cr100_stfirstoif1; + +/* CR100 - 0 */ +typedef enum { + AB8500_CODEC_CR100_STFIR_BUSY_READY, + AB8500_CODEC_CR100_STFIR_BUSY_NOT_READY +} t_ab8500_codec_cr100_stfir_busy; + +/* CR101 - 7 */ +typedef enum { + AB8500_CODEC_CR101_HSOFFST_MASK_MASKED, + AB8500_CODEC_CR101_HSOFFST_MASK_ENABLED +} t_ab8500_codec_cr101_hsoffst_mask; + +/* CR101 - 6 */ +typedef enum { + AB8500_CODEC_CR101_FIFOFULL_MASK_MASKED, + AB8500_CODEC_CR101_FIFOFULL_MASK_ENABLED +} t_ab8500_codec_cr101_fifofull_mask; + +/* CR101 - 5 */ +typedef enum { + AB8500_CODEC_CR101_FIFOEMPTY_MASK_MASKED, + AB8500_CODEC_CR101_FIFOEMPTY_MASK_ENABLED +} t_ab8500_codec_cr101_fifoempty_mask; + +/* CR101 - 4 */ +typedef enum { + AB8500_CODEC_CR101_DASAT_MASK_MASKED, + AB8500_CODEC_CR101_DASAT_MASK_ENABLED +} t_ab8500_codec_cr101_dasat_mask; + +/* CR101 - 3 */ +typedef enum { + AB8500_CODEC_CR101_ADSAT_MASK_MASKED, + AB8500_CODEC_CR101_ADSAT_MASK_ENABLED +} t_ab8500_codec_cr101_adsat_mask; + +/* CR101 - 2 */ +typedef enum { + AB8500_CODEC_CR101_ADDSP_MASK_MASKED, + AB8500_CODEC_CR101_ADDSP_MASK_ENABLED +} t_ab8500_codec_cr101_addsp_mask; + +/* CR101 - 1 */ +typedef enum { + AB8500_CODEC_CR101_DADSP_MASK_MASKED, + AB8500_CODEC_CR101_DADSP_MASK_ENABLED +} t_ab8500_codec_cr101_dadsp_mask; + +/* CR101 - 0 */ +typedef enum { + AB8500_CODEC_CR101_FIRSID_MASK_MASKED, + AB8500_CODEC_CR101_FIRSID_MASK_ENABLED +} t_ab8500_codec_cr101_firsid_mask; + +/* CR102 - Read Only */ +/* CR102 - 7 */ +typedef enum { + AB8500_CODEC_CR102_IT_HSOFFST_ON, + AB8500_CODEC_CR102_IT_HSOFFST_OFF +} t_ab8500_codec_cr102_it_hsoffst; + +/* CR102 - 6 */ +typedef enum { + AB8500_CODEC_CR102_IT_FIFOFULL_NOT_FULL, + AB8500_CODEC_CR102_IT_FIFOFULL_FULL +} t_ab8500_codec_cr102_it_fifofull; + +/* CR102 - 5 */ +typedef enum { + AB8500_CODEC_CR102_IT_FIFOEMPTY_NOT_EMPTY, + AB8500_CODEC_CR102_IT_FIFOEMPTY_EMPTY +} t_ab8500_codec_cr102_it_fifoempty; + +/* CR102 - 4 */ +typedef enum { + AB8500_CODEC_CR102_IT_DASAT_NO_SATURATION, + AB8500_CODEC_CR102_IT_DASAT_SATURATION +} t_ab8500_codec_cr102_it_dasat; + +/* CR102 - 3 */ +typedef enum { + AB8500_CODEC_CR102_IT_ADSAT_NO_SATURATION, + AB8500_CODEC_CR102_IT_ADSAT_SATURATION +} t_ab8500_codec_cr102_it_adsat; + +/* CR102 - 2 */ +typedef enum { + AB8500_CODEC_CR102_IT_ADDSP_NO_SATURATION, + AB8500_CODEC_CR102_IT_ADDSP_SATURATION +} t_ab8500_codec_cr102_it_addsp; + +/* CR102 - 1 */ +typedef enum { + AB8500_CODEC_CR102_IT_DADSP_NO_SATURATION, + AB8500_CODEC_CR102_IT_DADSP_SATURATION +} t_ab8500_codec_cr102_it_dadsp; + +/* CR102 - 0 */ +typedef enum { + AB8500_CODEC_CR102_IT_FIRSID_NO_SATURATION, + AB8500_CODEC_CR102_IT_FIRSID_SATURATION +} t_ab8500_codec_cr102_it_firsid; + +/* CR103 - 7 */ +typedef enum { + AB8500_CODEC_CR103_VSSREADY_MASK_MASKED, + AB8500_CODEC_CR103_VSSREADY_MASK_ENABLED +} t_ab8500_codec_cr103_vssready_mask; + +/* CR103 - 2 */ +typedef enum { + AB8500_CODEC_CR103_SHORTHSL_MASK_MASKED, + AB8500_CODEC_CR103_SHORTHSL_MASK_ENABLED +} t_ab8500_codec_cr103_shorthsl_mask; + +/* CR103 - 1 */ +typedef enum { + AB8500_CODEC_CR103_SHORTHSR_MASK_MASKED, + AB8500_CODEC_CR103_SHORTHSR_MASK_ENABLED +} t_ab8500_codec_cr103_shorthsr_mask; + +/* CR103 - 0 */ +typedef enum { + AB8500_CODEC_CR103_SHORTEAR_MASK_MASKED, + AB8500_CODEC_CR103_SHORTEAR_MASK_ENABLED +} t_ab8500_codec_cr103_shortear_mask; + +/* CR104 - Read Only */ +/* CR104 - 7 */ +typedef enum { + AB8500_CODEC_CR104_IT_VSSREADY_NOT_READY, + AB8500_CODEC_CR104_IT_VSSREADY_READY +} t_ab8500_codec_cr104_it_vssready; + +/* CR104 - 2 */ +typedef enum { + AB8500_CODEC_CR104_IT_SHORTHSL_NOT_DETECTED, + AB8500_CODEC_CR104_IT_SHORTHSL_DETECTED +} t_ab8500_codec_cr104_it_shorthsl; + +/* CR104 - 1 */ +typedef enum { + AB8500_CODEC_CR104_IT_SHORTHSR_NOT_DETECTED, + AB8500_CODEC_CR104_IT_SHORTHSR_DETECTED +} t_ab8500_codec_cr104_it_shorthsr; + +/* CR104 - 0 */ +typedef enum { + AB8500_CODEC_CR104_IT_SHORTEAR_NOT_DETECTED, + AB8500_CODEC_CR104_IT_SHORTEAR_DETECTED +} t_ab8500_codec_cr104_it_shortear; + +/* CR105 - 7 */ +/* In ab8500_codec.h */ + +/* CR105 - 5:0 */ +/* In ab8500_codec.h */ + +/* CR106 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR107 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR108 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR109 - 7:0 */ +/* In ab8500_codec.h */ + +/* CR110 - Read Only */ +/* CR110 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr110_bfifosamples; + +/* CR111 - Read Only */ +/* CR111 - 4:0 */ +typedef t_uint8 t_ab8500_codec_cr111_aud_ip_rev; + +/* CR27 - 6:5 */ +typedef enum { + AB8500_CODEC_CR27_IF1_BITCLK_OSR_32, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_64, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_128, + AB8500_CODEC_CR27_IF1_BITCLK_OSR_256 +} t_ab8500_codec_cr27_if1_bitclk_osr; + +/* CR27 - 2:1 */ +typedef enum { + AB8500_CODEC_CR27_IF0_BITCLK_OSR_32, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_64, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_128, + AB8500_CODEC_CR27_IF0_BITCLK_OSR_256 +} t_ab8500_codec_cr27_if0_bitclk_osr; + +/* CR28 - 1:0 */ +typedef enum { + AB8500_CODEC_CR28_IF0WL_16BITS, + AB8500_CODEC_CR28_IF0WL_20BITS, + AB8500_CODEC_CR28_IF0WL_24BITS, + AB8500_CODEC_CR28_IF0WL_32BITS +} t_ab8500_codec_cr28_if0wl; + +/* CR30 - 1:0 */ +typedef enum { + AB8500_CODEC_CR30_IF1WL_16BITS, + AB8500_CODEC_CR30_IF1WL_20BITS, + AB8500_CODEC_CR30_IF1WL_24BITS, + AB8500_CODEC_CR30_IF1WL_32BITS +} t_ab8500_codec_cr30_if1wl; + +/* CR105 - 7 */ +typedef enum { + AB8500_CODEC_CR105_BFIFOMSK_AD_DATA0_UNMASKED, + AB8500_CODEC_CR105_BFIFOMSK_AD_DATA0_MASKED +} t_ab8500_codec_cr105_bfifomsk; + +/* CR105 - 5:0 */ +typedef t_uint8 t_ab8500_codec_cr105_bfifoint; + +/* CR106 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr106_bfifotx; + +/* CR107 - 7:5 */ +typedef enum { + AB8500_CODEC_CR107_BFIFOEXSL_0_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_1_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_2_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_3_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_4_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_5_EXTRA_SLOT, + AB8500_CODEC_CR107_BFIFOEXSL_6_EXTRA_SLOT, +} t_ab8500_codec_cr107_bfifoexsl; + +/* CR107 - 4:2 */ +typedef enum { + AB8500_CODEC_CR107_PREBITCLK0_0_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_1_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_2_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_3_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_4_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_5_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_6_EXTRA_CLK, + AB8500_CODEC_CR107_PREBITCLK0_7_EXTRA_CLK +} t_ab8500_codec_cr107_prebitclk0; + +/* CR107 - 1 */ +typedef enum { + AB8500_CODEC_CR107_BFIFOMAST_SLAVE_MODE, + AB8500_CODEC_CR107_BFIFOMAST_MASTER_MODE +} t_ab8500_codec_cr107_bfifomast; + +/* CR107 - 0 */ +typedef enum { + AB8500_CODEC_CR107_BFIFORUN_STOPPED, + AB8500_CODEC_CR107_BFIFORUN_RUNNING +} t_ab8500_codec_cr107_bfiforun; + +/* CR108 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr108_bfifoframsw; + +/* CR109 - 7:0 */ +typedef t_uint8 t_ab8500_codec_cr109_bfifowakeup; + +typedef enum { + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_ZEROS, + AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE = 15, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED +} t_ab8500_codec_cr31_to_cr46_ad_data_allocation; + +typedef enum { + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT00, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT01, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT02, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT03, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT04, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT05, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT06, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT07, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT10, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT11, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT16, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT17, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT18, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT19, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT20, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT21, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT22, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT23, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT24, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT25, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT26, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT27, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT28, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT29, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT30, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT31, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED +} t_ab8500_codec_cr51_to_cr58_sltoda; + +/*configuration structure for AB8500 Codec*/ +typedef struct { + /* CR0 */ + t_ab8500_codec_cr0_powerup cr0_powerup; + t_ab8500_codec_cr0_enaana cr0_enaana; + + /* CR1 */ + t_ab8500_codec_cr1_swreset cr1_swreset; + + /* CR2 */ + t_ab8500_codec_cr2_enad1 cr2_enad1; + t_ab8500_codec_cr2_enad2 cr2_enad2; + t_ab8500_codec_cr2_enad3 cr2_enad3; + t_ab8500_codec_cr2_enad4 cr2_enad4; + t_ab8500_codec_cr2_enad5 cr2_enad5; + t_ab8500_codec_cr2_enad6 cr2_enad6; + + /* CR3 */ + t_ab8500_codec_cr3_enda1 cr3_enda1; + t_ab8500_codec_cr3_enda2 cr3_enda2; + t_ab8500_codec_cr3_enda3 cr3_enda3; + t_ab8500_codec_cr3_enda4 cr3_enda4; + t_ab8500_codec_cr3_enda5 cr3_enda5; + t_ab8500_codec_cr3_enda6 cr3_enda6; + + /* CR4 */ + t_ab8500_codec_cr4_lowpowhs cr4_lowpowhs; + t_ab8500_codec_cr4_lowpowdachs cr4_lowpowdachs; + t_ab8500_codec_cr4_lowpowear cr4_lowpowear; + t_ab8500_codec_cr4_ear_sel_cm cr4_ear_sel_cm; + t_ab8500_codec_cr4_hs_hp_en cr4_hs_hp_en; + + /* CR5 */ + t_ab8500_codec_cr5_enmic1 cr5_enmic1; + t_ab8500_codec_cr5_enmic2 cr5_enmic2; + t_ab8500_codec_cr5_enlinl cr5_enlinl; + t_ab8500_codec_cr5_enlinr cr5_enlinr; + t_ab8500_codec_cr5_mutmic1 cr5_mutmic1; + t_ab8500_codec_cr5_mutmic2 cr5_mutmic2; + t_ab8500_codec_cr5_mutlinl cr5_mutlinl; + t_ab8500_codec_cr5_mutlinr cr5_mutlinr; + + /* CR6 */ + t_ab8500_codec_cr6_endmic1 cr6_endmic1; + t_ab8500_codec_cr6_endmic2 cr6_endmic2; + t_ab8500_codec_cr6_endmic3 cr6_endmic3; + t_ab8500_codec_cr6_endmic4 cr6_endmic4; + t_ab8500_codec_cr6_endmic5 cr6_endmic5; + t_ab8500_codec_cr6_endmic6 cr6_endmic6; + + /* CR7 */ + t_ab8500_codec_cr7_mic1sel cr7_mic1sel; + t_ab8500_codec_cr7_linrsel cr7_linrsel; + t_ab8500_codec_cr7_endrvhsl cr7_endrvhsl; + t_ab8500_codec_cr7_endrvhsr cr7_endrvhsr; + t_ab8500_codec_cr7_enadcmic cr7_enadcmic; + t_ab8500_codec_cr7_enadclinl cr7_enadclinl; + t_ab8500_codec_cr7_enadclinr cr7_enadclinr; + + /* CR8 */ + t_ab8500_codec_cr8_cp_dis_pldwn cr8_cp_dis_pldwn; + t_ab8500_codec_cr8_enear cr8_enear; + t_ab8500_codec_cr8_enhsl cr8_enhsl; + t_ab8500_codec_cr8_enhsr cr8_enhsr; + t_ab8500_codec_cr8_enhfl cr8_enhfl; + t_ab8500_codec_cr8_enhfr cr8_enhfr; + t_ab8500_codec_cr8_envibl cr8_envibl; + t_ab8500_codec_cr8_envibr cr8_envibr; + + /* CR9 */ + t_ab8500_codec_cr9_endacear cr9_endacear; + t_ab8500_codec_cr9_endachsl cr9_endachsl; + t_ab8500_codec_cr9_endachsr cr9_endachsr; + t_ab8500_codec_cr9_endachfl cr9_endachfl; + t_ab8500_codec_cr9_endachfr cr9_endachfr; + t_ab8500_codec_cr9_endacvibl cr9_endacvibl; + t_ab8500_codec_cr9_endacvibr cr9_endacvibr; + + /* CR10 */ + t_ab8500_codec_cr10_muteear cr10_muteear; + t_ab8500_codec_cr10_mutehsl cr10_mutehsl; + t_ab8500_codec_cr10_mutehsr cr10_mutehsr; + + /* CR11 */ + t_ab8500_codec_cr11_enshortpwd cr11_enshortpwd; + t_ab8500_codec_cr11_earshortdis cr11_earshortdis; + t_ab8500_codec_cr11_hsshortdis cr11_hsshortdis; + t_ab8500_codec_cr11_hspullden cr11_hspullden; + t_ab8500_codec_cr11_hsoscen cr11_hsoscen; + t_ab8500_codec_cr11_hsfaden cr11_hsfaden; + t_ab8500_codec_cr11_hszcddis cr11_hszcddis; + + /* CR12 */ + t_ab8500_codec_cr12_encphs cr12_encphs; + t_ab8500_codec_cr12_hsautoen cr12_hsautoen; + + /* CR13 */ + t_ab8500_codec_cr13_envdet_hthresh cr13_envdet_hthresh; + t_ab8500_codec_cr13_envdet_lthresh cr13_envdet_lthresh; + + /* CR14 */ + t_ab8500_codec_cr14_smpslven cr14_smpslven; + t_ab8500_codec_cr14_envdetsmpsen cr14_envdetsmpsen; + t_ab8500_codec_cr14_cplven cr14_cplven; + t_ab8500_codec_cr14_envdetcpen cr14_envdetcpen; + t_ab8500_codec_cr14_envet_time cr14_envet_time; + + /* CR15 */ + t_ab8500_codec_cr15_pwmtovibl cr15_pwmtovibl; + t_ab8500_codec_cr15_pwmtovibr cr15_pwmtovibr; + t_ab8500_codec_cr15_pwmlctrl cr15_pwmlctrl; + t_ab8500_codec_cr15_pwmrctrl cr15_pwmrctrl; + t_ab8500_codec_cr15_pwmnlctrl cr15_pwmnlctrl; + t_ab8500_codec_cr15_pwmplctrl cr15_pwmplctrl; + t_ab8500_codec_cr15_pwmnrctrl cr15_pwmnrctrl; + t_ab8500_codec_cr15_pwmprctrl cr15_pwmprctrl; + + /* CR16 */ + t_ab8500_codec_cr16_pwmnlpol cr16_pwmnlpol; + t_ab8500_codec_cr16_pwmnldutycycle cr16_pwmnldutycycle; + + /* CR17 */ + t_ab8500_codec_cr17_pwmplpol cr17_pwmplpol; + t_ab8500_codec_cr17_pwmpldutycycle cr17_pwmpldutycycle; + + /* CR18 */ + t_ab8500_codec_cr18_pwmnrpol cr18_pwmnrpol; + t_ab8500_codec_cr18_pwmnrdutycycle cr18_pwmnrdutycycle; + + /* CR19 */ + t_ab8500_codec_cr19_pwmprpol cr19_pwmprpol; + t_ab8500_codec_cr19_pwmprdutycycle cr19_pwmprdutycycle; + + /* CR20 */ + t_ab8500_codec_cr20_en_se_mic1 cr20_en_se_mic1; + t_ab8500_codec_cr20_low_pow_mic1 cr20_low_pow_mic1; + t_ab8500_codec_cr20_mic1_gain cr20_mic1_gain; + + /* CR21 */ + t_ab8500_codec_cr21_en_se_mic2 cr21_en_se_mic2; + t_ab8500_codec_cr21_low_pow_mic2 cr21_low_pow_mic2; + t_ab8500_codec_cr21_mic2_gain cr21_mic2_gain; + + /* CR22 */ + t_ab8500_codec_cr22_hsl_gain cr22_hsl_gain; + t_ab8500_codec_cr22_hsr_gain cr22_hsr_gain; + + /* CR23 */ + t_ab8500_codec_cr23_linl_gain cr23_linl_gain; + t_ab8500_codec_cr23_linr_gain cr23_linr_gain; + + /* CR24 */ + t_ab8500_codec_cr24_lintohsl_gain cr24_lintohsl_gain; + + /* CR25 */ + t_ab8500_codec_cr25_lintohsr_gain cr25_lintohsr_gain; + + /* CR26 */ + t_ab8500_codec_cr26_ad1nh cr26_ad1nh; + t_ab8500_codec_cr26_ad2nh cr26_ad2nh; + t_ab8500_codec_cr26_ad3nh cr26_ad3nh; + t_ab8500_codec_cr26_ad4nh cr26_ad4nh; + t_ab8500_codec_cr26_ad1_voice cr26_ad1_voice; + t_ab8500_codec_cr26_ad2_voice cr26_ad2_voice; + t_ab8500_codec_cr26_ad3_voice cr26_ad3_voice; + t_ab8500_codec_cr26_ad4_voice cr26_ad4_voice; + + /* CR27 */ + t_ab8500_codec_cr27_en_mastgen cr27_en_mastgen; + t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr; + t_ab8500_codec_cr27_enfs_bitclk1 cr27_enfs_bitclk1; + t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr; + t_ab8500_codec_cr27_enfs_bitclk0 cr27_enfs_bitclk0; + + /* CR28 */ + t_ab8500_codec_cr28_fsync0p cr28_fsync0p; + t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p; + t_ab8500_codec_cr28_if0del cr28_if0del; + t_ab8500_codec_cr28_if0format cr28_if0format; + t_ab8500_codec_cr28_if0wl cr28_if0wl; + + /* CR29 */ + t_ab8500_codec_cr29_if0datoif1ad cr29_if0datoif1ad; + t_ab8500_codec_cr29_if0cktoif1ck cr29_if0cktoif1ck; + t_ab8500_codec_cr29_if1master cr29_if1master; + t_ab8500_codec_cr29_if1datoif0ad cr29_if1datoif0ad; + t_ab8500_codec_cr29_if1cktoif0ck cr29_if1cktoif0ck; + t_ab8500_codec_cr29_if0master cr29_if0master; + t_ab8500_codec_cr29_if0bfifoen cr29_if0bfifoen; + + /* CR30 */ + t_ab8500_codec_cr30_fsync1p cr30_fsync1p; + t_ab8500_codec_cr30_bitclk1p cr30_bitclk1p; + t_ab8500_codec_cr30_if1del cr30_if1del; + t_ab8500_codec_cr30_if1format cr30_if1format; + t_ab8500_codec_cr30_if1wl cr30_if1wl; + + /* CR31 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot1; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot0; + + /* CR32 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot3; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot2; + + /* CR33 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot5; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot4; + + /* CR34 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot7; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot6; + + /* CR35 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot9; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot8; + + /* CR36 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot11; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot10; + + /* CR37 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot13; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot12; + + /* CR38 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot15; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot14; + + /* CR39 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot17; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot16; + + /* CR40 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot19; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot18; + + /* CR41 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot21; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot20; + + /* CR42 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot23; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot22; + + /* CR43 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot25; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot24; + + /* CR44 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot27; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot26; + + /* CR45 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot29; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot28; + + /* CR46 */ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot31; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot30; + + /* CR47 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl7; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl6; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl5; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl4; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl3; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl2; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl1; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl0; + + /* CR48 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl15; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl14; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl13; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl12; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl11; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl10; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl9; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl8; + + /* CR49 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl23; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl22; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl21; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl20; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl19; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl18; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl17; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl16; + + /* CR50 */ + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl31; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl30; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl29; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl28; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl27; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl26; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl25; + t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl24; + + /* CR51 */ + t_ab8500_codec_cr51_da12_voice cr51_da12_voice; + t_ab8500_codec_cr51_swapda12_34 cr51_swapda12_34; + t_ab8500_codec_cr51_sldai7toslado1 cr51_sldai7toslado1; + t_ab8500_codec_cr51_to_cr58_sltoda cr51_sltoda1; + + /* CR52 */ + t_ab8500_codec_cr52_sldai8toslado2 cr52_sldai8toslado2; + t_ab8500_codec_cr51_to_cr58_sltoda cr52_sltoda2; + + /* CR53 */ + t_ab8500_codec_cr53_da34_voice cr53_da34_voice; + t_ab8500_codec_cr53_sldai7toslado3 cr53_sldai7toslado3; + t_ab8500_codec_cr51_to_cr58_sltoda cr53_sltoda3; + + /* CR54 */ + t_ab8500_codec_cr54_sldai8toslado4 cr54_sldai8toslado4; + t_ab8500_codec_cr51_to_cr58_sltoda cr54_sltoda4; + + /* CR55 */ + t_ab8500_codec_cr55_da56_voice cr55_da56_voice; + t_ab8500_codec_cr55_sldai7toslado5 cr55_sldai7toslado5; + t_ab8500_codec_cr51_to_cr58_sltoda cr55_sltoda5; + + /* CR56 */ + t_ab8500_codec_cr56_sldai8toslado6 cr56_sldai8toslado6; + t_ab8500_codec_cr51_to_cr58_sltoda cr56_sltoda6; + + /* CR57 */ + t_ab8500_codec_cr57_sldai8toslado7 cr57_sldai8toslado7; + t_ab8500_codec_cr51_to_cr58_sltoda cr57_sltoda7; + + /* CR58 */ + t_ab8500_codec_cr58_sldai7toslado8 cr58_sldai7toslado8; + t_ab8500_codec_cr51_to_cr58_sltoda cr58_sltoda8; + + /* CR59 */ + t_ab8500_codec_cr59_parlhf cr59_parlhf; + t_ab8500_codec_cr59_parlvib cr59_parlvib; + t_ab8500_codec_cr59_classdvib1_swapen cr59_classdvib1_swapen; + t_ab8500_codec_cr59_classdvib2_swapen cr59_classdvib2_swapen; + t_ab8500_codec_cr59_classdhfl_swapen cr59_classdhfl_swapen; + t_ab8500_codec_cr59_classdhfr_swapen cr59_classdhfr_swapen; + + /* CR60 */ + t_ab8500_codec_cr60_classd_firbyp cr60_classd_firbyp; + t_ab8500_codec_cr60_classd_highvolen cr60_classd_highvolen; + + /* CR61 */ + t_ab8500_codec_cr61_classddith_hpgain cr61_classddith_hpgain; + t_ab8500_codec_cr61_classddith_wgain cr61_classddith_wgain; + + /* CR62 */ + t_ab8500_codec_cr62_dmic1sinc3 cr62_dmic1sinc3; + t_ab8500_codec_cr62_dmic2sinc3 cr62_dmic2sinc3; + t_ab8500_codec_cr62_dmic3sinc3 cr62_dmic3sinc3; + t_ab8500_codec_cr62_dmic4sinc3 cr62_dmic4sinc3; + t_ab8500_codec_cr62_dmic5sinc3 cr62_dmic5sinc3; + t_ab8500_codec_cr62_dmic6sinc3 cr62_dmic6sinc3; + + /* CR63 */ + t_ab8500_codec_cr63_datohslen cr63_datohslen; + t_ab8500_codec_cr63_datohsren cr63_datohsren; + t_ab8500_codec_cr63_ad1sel cr63_ad1sel; + t_ab8500_codec_cr63_ad2sel cr63_ad2sel; + t_ab8500_codec_cr63_ad3sel cr63_ad3sel; + t_ab8500_codec_cr63_ad5sel cr63_ad5sel; + t_ab8500_codec_cr63_ad6sel cr63_ad6sel; + t_ab8500_codec_cr63_ancsel cr63_ancsel; + + /* CR64 */ + t_ab8500_codec_cr64_datohfren cr64_datohfren; + t_ab8500_codec_cr64_datohflen cr64_datohflen; + t_ab8500_codec_cr64_hfrsel cr64_hfrsel; + t_ab8500_codec_cr64_hflsel cr64_hflsel; + t_ab8500_codec_cr64_stfir1sel cr64_stfir1sel; + t_ab8500_codec_cr64_stfir2sel cr64_stfir2sel; + + /* CR65 */ + t_ab8500_codec_cr65_fadedis_ad1 cr65_fadedis_ad1; + t_ab8500_codec_cr65_ad1gain cr65_ad1gain; + + /* CR66 */ + t_ab8500_codec_cr66_fadedis_ad2 cr66_fadedis_ad2; + t_ab8500_codec_cr66_ad2gain cr66_ad2gain; + + /* CR67 */ + t_ab8500_codec_cr67_fadedis_ad3 cr67_fadedis_ad3; + t_ab8500_codec_cr67_ad3gain cr67_ad3gain; + + /* CR68 */ + t_ab8500_codec_cr68_fadedis_ad4 cr68_fadedis_ad4; + t_ab8500_codec_cr68_ad4gain cr68_ad4gain; + + /* CR69 */ + t_ab8500_codec_cr69_fadedis_ad5 cr69_fadedis_ad5; + t_ab8500_codec_cr69_ad5gain cr69_ad5gain; + + /* CR70 */ + t_ab8500_codec_cr70_fadedis_ad6 cr70_fadedis_ad6; + t_ab8500_codec_cr70_ad6gain cr70_ad6gain; + + /* CR71 */ + t_ab8500_codec_cr71_fadedis_da1 cr71_fadedis_da1; + t_ab8500_codec_cr71_da1gain cr71_da1gain; + + /* CR72 */ + t_ab8500_codec_cr72_fadedis_da2 cr72_fadedis_da2; + t_ab8500_codec_cr72_da2gain cr72_da2gain; + + /* CR73 */ + t_ab8500_codec_cr73_fadedis_da3 cr73_fadedis_da3; + t_ab8500_codec_cr73_da3gain cr73_da3gain; + + /* CR74 */ + t_ab8500_codec_cr74_fadedis_da4 cr74_fadedis_da4; + t_ab8500_codec_cr74_da4gain cr74_da4gain; + + /* CR75 */ + t_ab8500_codec_cr75_fadedis_da5 cr75_fadedis_da5; + t_ab8500_codec_cr75_da5gain cr75_da5gain; + + /* CR76 */ + t_ab8500_codec_cr76_fadedis_da6 cr76_fadedis_da6; + t_ab8500_codec_cr76_da6gain cr76_da6gain; + + /* CR77 */ + t_ab8500_codec_cr77_fadedis_ad1l cr77_fadedis_ad1l; + t_ab8500_codec_cr77_ad1lbgain_to_hfl cr77_ad1lbgain_to_hfl; + + /* CR78 */ + t_ab8500_codec_cr78_fadedis_ad2l cr78_fadedis_ad2l; + t_ab8500_codec_cr78_ad2lbgain_to_hfr cr78_ad2lbgain_to_hfr; + + /* CR79 */ + t_ab8500_codec_cr79_hssinc1 cr79_hssinc1; + t_ab8500_codec_cr79_fadedis_hsl cr79_fadedis_hsl; + t_ab8500_codec_cr79_hsldgain cr79_hsldgain; + + /* CR80 */ + t_ab8500_codec_cr80_fade_speed cr80_fade_speed; + t_ab8500_codec_cr80_fadedis_hsr cr80_fadedis_hsr; + t_ab8500_codec_cr80_hsrdgain cr80_hsrdgain; + + /* CR81 */ + t_ab8500_codec_cr81_stfir1gain cr81_stfir1gain; + + /* CR82 */ + t_ab8500_codec_cr82_stfir2gain cr82_stfir2gain; + + /* CR83 */ + t_ab8500_codec_cr83_enanc cr83_enanc; + t_ab8500_codec_cr83_anciirinit cr83_anciirinit; + t_ab8500_codec_cr83_ancfirupdate cr83_ancfirupdate; + + /* CR84 */ + t_ab8500_codec_cr84_ancinshift cr84_ancinshift; + + /* CR85 */ + t_ab8500_codec_cr85_ancfiroutshift cr85_ancfiroutshift; + + /* CR86 */ + t_ab8500_codec_cr86_ancshiftout cr86_ancshiftout; + + /* CR87 */ + t_ab8500_codec_cr87_ancfircoeff_msb cr87_ancfircoeff_msb; + + /* CR88 */ + t_ab8500_codec_cr88_ancfircoeff_lsb cr88_ancfircoeff_lsb; + + /* CR89 */ + t_ab8500_codec_cr89_anciircoeff_msb cr89_anciircoeff_msb; + + /* CR90 */ + t_ab8500_codec_cr90_anciircoeff_lsb cr90_anciircoeff_lsb; + + /* CR91 */ + t_ab8500_codec_cr91_ancwarpdel_msb cr91_ancwarpdel_msb; + + /* CR92 */ + t_ab8500_codec_cr92_ancwarpdel_lsb cr92_ancwarpdel_lsb; + + /* CR93 */ + t_ab8500_codec_cr93_ancfirpeak_msb cr93_ancfirpeak_msb; + + /* CR94 */ + t_ab8500_codec_cr94_ancfirpeak_lsb cr94_ancfirpeak_lsb; + + /* CR95 */ + t_ab8500_codec_cr95_anciirpeak_msb cr95_anciirpeak_msb; + + /* CR96 */ + t_ab8500_codec_cr96_anciirpeak_lsb cr96_anciirpeak_lsb; + + /* CR97 */ + t_ab8500_codec_cr97_stfir_set cr97_stfir_set; + t_ab8500_codec_cr97_stfir_addr cr97_stfir_addr; + + /* CR98 */ + t_ab8500_codec_cr98_stfir_coeff_msb cr98_stfir_coeff_msb; + + /* CR99 */ + t_ab8500_codec_cr99_stfir_coeff_lsb cr99_stfir_coeff_lsb; + + /* CR100 */ + t_ab8500_codec_cr100_enstfirs cr100_enstfirs; + t_ab8500_codec_cr100_stfirstoif1 cr100_stfirstoif1; + t_ab8500_codec_cr100_stfir_busy cr100_stfir_busy; + + /* CR101 */ + t_ab8500_codec_cr101_hsoffst_mask cr101_hsoffst_mask; + t_ab8500_codec_cr101_fifofull_mask cr101_fifofull_mask; + t_ab8500_codec_cr101_fifoempty_mask cr101_fifoempty_mask; + t_ab8500_codec_cr101_dasat_mask cr101_dasat_mask; + t_ab8500_codec_cr101_adsat_mask cr101_adsat_mask; + t_ab8500_codec_cr101_addsp_mask cr101_addsp_mask; + t_ab8500_codec_cr101_dadsp_mask cr101_dadsp_mask; + t_ab8500_codec_cr101_firsid_mask cr101_firsid_mask; + + /* CR102 */ + t_ab8500_codec_cr102_it_hsoffst cr102_it_hsoffst; + t_ab8500_codec_cr102_it_fifofull cr102_it_fifofull; + t_ab8500_codec_cr102_it_fifoempty cr102_it_fifoempty; + t_ab8500_codec_cr102_it_dasat cr102_it_dasat; + t_ab8500_codec_cr102_it_adsat cr102_it_adsat; + t_ab8500_codec_cr102_it_addsp cr102_it_addsp; + t_ab8500_codec_cr102_it_dadsp cr102_it_dadsp; + t_ab8500_codec_cr102_it_firsid cr102_it_firsid; + + /* CR103 */ + t_ab8500_codec_cr103_vssready_mask cr103_vssready_mask; + t_ab8500_codec_cr103_shorthsl_mask cr103_shorthsl_mask; + t_ab8500_codec_cr103_shorthsr_mask cr103_shorthsr_mask; + t_ab8500_codec_cr103_shortear_mask cr103_shortear_mask; + + /* CR104 */ + t_ab8500_codec_cr104_it_vssready cr104_it_vssready; + t_ab8500_codec_cr104_it_shorthsl cr104_it_shorthsl; + t_ab8500_codec_cr104_it_shorthsr cr104_it_shorthsr; + t_ab8500_codec_cr104_it_shortear cr104_it_shortear; + + /* CR105 */ + t_ab8500_codec_cr105_bfifomsk cr105_bfifomsk; + t_ab8500_codec_cr105_bfifoint cr105_bfifoint; + + /* CR106 */ + t_ab8500_codec_cr106_bfifotx cr106_bfifotx; + + /* CR107 */ + t_ab8500_codec_cr107_bfifoexsl cr107_bfifoexsl; + t_ab8500_codec_cr107_prebitclk0 cr107_prebitclk0; + t_ab8500_codec_cr107_bfifomast cr107_bfifomast; + t_ab8500_codec_cr107_bfiforun cr107_bfiforun; + + /* CR108 */ + t_ab8500_codec_cr108_bfifoframsw cr108_bfifoframsw; + + /* CR109 */ + t_ab8500_codec_cr109_bfifowakeup cr109_bfifowakeup; + + /* CR110 */ + t_ab8500_codec_cr110_bfifosamples cr110_bfifosamples; + + /* CR111 */ + t_ab8500_codec_cr111_aud_ip_rev cr111_aud_ip_rev; + +} t_ab8500_codec_configuration; + +typedef enum { + AB8500_CODEC_DIRECTION_IN, + AB8500_CODEC_DIRECTION_OUT, + AB8500_CODEC_DIRECTION_INOUT +} t_ab8500_codec_direction; + +typedef enum { + AB8500_CODEC_AUDIO_INTERFACE_0, + AB8500_CODEC_AUDIO_INTERFACE_1 +} t_ab8500_codec_audio_interface; + +typedef enum { + AB8500_CODEC_MODE_HIFI, + AB8500_CODEC_MODE_VOICE, + AB8500_CODEC_MODE_MANUAL_SETTING +} t_ab8500_codec_mode; + +typedef enum { + AB8500_CODEC_DEST_HEADSET, + AB8500_CODEC_DEST_EARPIECE, + AB8500_CODEC_DEST_HANDSFREE, + AB8500_CODEC_DEST_VIBRATOR_L, + AB8500_CODEC_DEST_VIBRATOR_R, + AB8500_CODEC_DEST_FM_TX, + AB8500_CODEC_DEST_ALL +} t_ab8500_codec_dest; + +typedef enum { + AB8500_CODEC_SRC_LINEIN, + AB8500_CODEC_SRC_MICROPHONE_1A, + AB8500_CODEC_SRC_MICROPHONE_1B, + AB8500_CODEC_SRC_MICROPHONE_2, + AB8500_CODEC_SRC_D_MICROPHONE_1, + AB8500_CODEC_SRC_D_MICROPHONE_2, + AB8500_CODEC_SRC_D_MICROPHONE_3, + AB8500_CODEC_SRC_D_MICROPHONE_4, + AB8500_CODEC_SRC_D_MICROPHONE_5, + AB8500_CODEC_SRC_D_MICROPHONE_6, + AB8500_CODEC_SRC_D_MICROPHONE_12, + AB8500_CODEC_SRC_D_MICROPHONE_34, + AB8500_CODEC_SRC_D_MICROPHONE_56, + AB8500_CODEC_SRC_FM_RX, + AB8500_CODEC_SRC_ALL +} t_ab8500_codec_src; + +typedef struct { + t_uint8 slave_address_of_ab8500_codec; + t_ab8500_codec_direction ab8500_codec_direction; + t_ab8500_codec_mode ab8500_codec_mode_in; + t_ab8500_codec_mode ab8500_codec_mode_out; + t_ab8500_codec_audio_interface audio_interface; + t_ab8500_codec_src ab8500_codec_src; + t_ab8500_codec_dest ab8500_codec_dest; + t_uint8 in_left_volume; + t_uint8 in_right_volume; + t_uint8 out_left_volume; + t_uint8 out_right_volume; + + t_ab8500_codec_configuration ab8500_codec_configuration; +} t_ab8500_codec_system_context; + +#endif /* _AB8500_CODECP_H_ */ + +/* End of file AB8500_CODECP.h */ diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h new file mode 100644 index 00000000000..a5b8a57f341 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h @@ -0,0 +1,329 @@ +/*****************************************************************************/ +/** +* © ST-Ericsson, 2009 - All rights reserved +* Reproduction and Communication of this document is strictly prohibited +* unless specifically authorized in writing by ST-Ericsson +* +* \brief Public header file for AB8500 Codec +* \author ST-Ericsson +*/ +/*****************************************************************************/ + +#ifndef _AB8500_CODEC_V1_0_H_ +#define _AB8500_CODEC_V1_0_H_ + +/*--------------------------------------------------------------------- + * Includes + *--------------------------------------------------------------------*/ +#include "hcl_defs.h" +#include "debug.h" +#include <mach/ab8500_codec_p_v1_0.h> +/*--------------------------------------------------------------------- + * Define + *--------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { + AB8500_CODEC_OK, + AB8500_CODEC_ERROR, + AB8500_CODEC_UNSUPPORTED_FEATURE, + AB8500_CODEC_INVALID_PARAMETER, + AB8500_CODEC_CONFIG_NOT_COHERENT, + AB8500_CODEC_TRANSACTION_FAILED + } t_ab8500_codec_error; + + typedef enum { + AB8500_CODEC_SRC_STATE_DISABLE, + AB8500_CODEC_SRC_STATE_ENABLE + } t_ab8500_codec_src_state; + + typedef enum { + AB8500_CODEC_DEST_STATE_DISABLE, + AB8500_CODEC_DEST_STATE_ENABLE + } t_ab8500_codec_dest_state; + + typedef enum { + AB8500_CODEC_MASTER_MODE_DISABLE, + AB8500_CODEC_MASTER_MODE_ENABLE + } t_ab8500_codec_master_mode; + + typedef enum { + AB8500_CODEC_SLOT0, + AB8500_CODEC_SLOT1, + AB8500_CODEC_SLOT2, + AB8500_CODEC_SLOT3, + AB8500_CODEC_SLOT4, + AB8500_CODEC_SLOT5, + AB8500_CODEC_SLOT6, + AB8500_CODEC_SLOT7, + AB8500_CODEC_SLOT8, + AB8500_CODEC_SLOT9, + AB8500_CODEC_SLOT10, + AB8500_CODEC_SLOT11, + AB8500_CODEC_SLOT12, + AB8500_CODEC_SLOT13, + AB8500_CODEC_SLOT14, + AB8500_CODEC_SLOT15, + AB8500_CODEC_SLOT16, + AB8500_CODEC_SLOT17, + AB8500_CODEC_SLOT18, + AB8500_CODEC_SLOT19, + AB8500_CODEC_SLOT20, + AB8500_CODEC_SLOT21, + AB8500_CODEC_SLOT22, + AB8500_CODEC_SLOT23, + AB8500_CODEC_SLOT24, + AB8500_CODEC_SLOT25, + AB8500_CODEC_SLOT26, + AB8500_CODEC_SLOT27, + AB8500_CODEC_SLOT28, + AB8500_CODEC_SLOT29, + AB8500_CODEC_SLOT30, + AB8500_CODEC_SLOT31, + AB8500_CODEC_SLOT_UNDEFINED + } t_ab8500_codec_slot; + + typedef enum { + AB8500_CODEC_DA_CHANNEL_NUMBER_1, + AB8500_CODEC_DA_CHANNEL_NUMBER_2, + AB8500_CODEC_DA_CHANNEL_NUMBER_3, + AB8500_CODEC_DA_CHANNEL_NUMBER_4, + AB8500_CODEC_DA_CHANNEL_NUMBER_5, + AB8500_CODEC_DA_CHANNEL_NUMBER_6, + AB8500_CODEC_DA_CHANNEL_NUMBER_7, + AB8500_CODEC_DA_CHANNEL_NUMBER_8, + AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED + } t_ab8500_codec_da_channel_number; + + typedef struct { + t_ab8500_codec_cr105_bfifomsk cr105_bfifomsk; + t_ab8500_codec_cr105_bfifoint cr105_bfifoint; + t_ab8500_codec_cr106_bfifotx cr106_bfifotx; + t_ab8500_codec_cr107_bfifoexsl cr107_bfifoexsl; + t_ab8500_codec_cr107_prebitclk0 cr107_prebitclk0; + t_ab8500_codec_cr107_bfifomast cr107_bfifomast; + t_ab8500_codec_cr107_bfiforun cr107_bfiforun; + t_ab8500_codec_cr108_bfifoframsw cr108_bfifoframsw; + t_ab8500_codec_cr109_bfifowakeup cr109_bfifowakeup; + } t_ab8500_codec_burst_fifo_config; + + typedef struct { + t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr; + t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr; + t_ab8500_codec_cr28_if0wl cr28_if0wl; + t_ab8500_codec_cr30_if1wl cr30_if1wl; + t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p; + t_ab8500_codec_cr28_if0del cr28_if0del; + } t_ab8500_codec_tdm_config; + +/************************************************************/ +/*--------------------------------------------------------------------- + * Exported APIs + *--------------------------------------------------------------------*/ +/* Initialization */ + t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8 + slave_address_of_codec); + t_ab8500_codec_error AB8500_CODEC_Reset(void); + +/* Audio Codec basic configuration */ + t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction, + IN + t_ab8500_codec_mode + ab8500_codec_mode_in, + IN + t_ab8500_codec_mode + ab8500_codec_mode_out, + IN + t_ab8500_codec_tdm_config + const *const + p_tdm_config); + t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src + ab8500_codec_src); + t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest + ab8500_codec_dest); + +/* Burst FIFO configuration */ + t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN + t_ab8500_codec_burst_fifo_config + const *const + p_burst_fifo_config); + t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void); + t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void); + +/* Audio Codec Master mode configuration */ + t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN + t_ab8500_codec_master_mode + mode); + +/* APIs to be implemented by user */ + t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset, + IN t_uint8 count, + IN t_uint8 * p_data); + t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset, + IN t_uint8 count, + IN t_uint8 * p_dummy_data, + IN t_uint8 * p_data); + +/* Volume Management */ + t_ab8500_codec_error AB8500_CODEC_SetSrcVolume(IN t_ab8500_codec_src + src_device, + IN t_uint8 + in_left_volume, + IN t_uint8 + in_right_volume); + t_ab8500_codec_error AB8500_CODEC_SetDestVolume(IN t_ab8500_codec_dest + dest_device, + IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume); + +/* Power management */ + t_ab8500_codec_error AB8500_CODEC_PowerDown(void); + t_ab8500_codec_error AB8500_CODEC_PowerUp(void); + +/* Interface Management */ + t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN + t_ab8500_codec_audio_interface + audio_interface); + t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT + t_ab8500_codec_audio_interface + * p_audio_interface); + +/* Slot Allocation */ + t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); + t_ab8500_codec_error AB8500_CODEC_DASlotAllocation(IN + t_ab8500_codec_da_channel_number + channel_number, + IN + t_ab8500_codec_cr51_to_cr58_sltoda + slot); + +/* Loopback Management */ + t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume); + t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void); + +/* Bypass Management */ + t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void); + t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void); + +/* Power Control Management */ + t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); + t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN + t_ab8500_codec_dest + dest_device, + t_ab8500_codec_dest_state + state); + +/* Version Management */ + t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version); + +#if 0 +/* Debug management */ + t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level); + t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level * + p_dbg_level); +#endif + +/* +** following is added by $kardad$ +*/ + +/* duplicate copy of enum from msp.h */ +/* for MSPConfiguration.in_clock_freq parameter to select msp clock freq */ + typedef enum { + CODEC_MSP_INPUT_FREQ_1MHZ = 1024, + CODEC_MSP_INPUT_FREQ_2MHZ = 2048, + CODEC_MSP_INPUT_FREQ_3MHZ = 3072, + CODEC_MSP_INPUT_FREQ_4MHZ = 4096, + CODEC_MSP_INPUT_FREQ_5MHZ = 5760, + CODEC_MSP_INPUT_FREQ_6MHZ = 6144, + CODEC_MSP_INPUT_FREQ_8MHZ = 8192, + CODEC_MSP_INPUT_FREQ_11MHZ = 11264, + CODEC_MSP_INPUT_FREQ_12MHZ = 12288, + CODEC_MSP_INPUT_FREQ_16MHZ = 16384, + CODEC_MSP_INPUT_FREQ_22MHZ = 22579, + CODEC_MSP_INPUT_FREQ_24MHZ = 24576, + CODEC_MSP_INPUT_FREQ_48MHZ = 49152 + } codec_msp_in_clock_freq_type; + +/* msp clock source internal/external for srg_clock_sel */ + typedef enum { + CODEC_MSP_APB_CLOCK = 0, + CODEC_MSP_SCK_CLOCK = 2, + CODEC_MSP_SCK_SYNC_CLOCK = 3 + } codec_msp_srg_clock_sel_type; + +/* Sample rate supported by Codec */ + + typedef enum { + CODEC_FREQUENCY_DONT_CHANGE = -100, + CODEC_SAMPLING_FREQ_RESET = -1, + CODEC_SAMPLING_FREQ_MINLIMIT = 7, + CODEC_SAMPLING_FREQ_8KHZ = 8, /*default */ + CODEC_SAMPLING_FREQ_11KHZ = 11, + CODEC_SAMPLING_FREQ_12KHZ = 12, + CODEC_SAMPLING_FREQ_16KHZ = 16, + CODEC_SAMPLING_FREQ_22KHZ = 22, + CODEC_SAMPLING_FREQ_24KHZ = 24, + CODEC_SAMPLING_FREQ_32KHZ = 32, + CODEC_SAMPLING_FREQ_44KHZ = 44, + CODEC_SAMPLING_FREQ_48KHZ = 48, + CODEC_SAMPLING_FREQ_64KHZ = 64, /*the frequencies below this line are not supported in stw5094A */ + CODEC_SAMPLING_FREQ_88KHZ = 88, + CODEC_SAMPLING_FREQ_96KHZ = 96, + CODEC_SAMPLING_FREQ_128KHZ = 128, + CODEC_SAMPLING_FREQ_176KHZ = 176, + CODEC_SAMPLING_FREQ_192KHZ = 192, + CODEC_SAMPLING_FREQ_MAXLIMIT = 193 + } t_codec_sample_frequency; + +#define RESET -1 +#define DEFAULT -100 +/***********************************************************/ +/* +** following stuff is added to compile code without debug print support $kardad$ +*/ + +#define DBGEXIT(cr) +#define DBGEXIT0(cr) +#define DBGEXIT1(cr,ch,p1) +#define DBGEXIT2(cr,ch,p1,p2) +#define DBGEXIT3(cr,ch,p1,p2,p3) +#define DBGEXIT4(cr,ch,p1,p2,p3,p4) +#define DBGEXIT5(cr,ch,p1,p2,p3,p4,p5) +#define DBGEXIT6(cr,ch,p1,p2,p3,p4,p5,p6) + +#define DBGENTER() +#define DBGENTER0() +#define DBGENTER1(ch,p1) +#define DBGENTER2(ch,p1,p2) +#define DBGENTER3(ch,p1,p2,p3) +#define DBGENTER4(ch,p1,p2,p3,p4) +#define DBGENTER5(ch,p1,p2,p3,p4,p5) +#define DBGENTER6(ch,p1,p2,p3,p4,p5,p6) + +#define DBGPRINT(dbg_level,dbg_string) +#define DBGPRINTHEX(dbg_level,dbg_string,uint32) +#define DBGPRINTDEC(dbg_level,dbg_string,uint32) +/***********************************************************/ + +#ifdef __cplusplus +} /* allow C++ to use these headers */ +#endif /* __cplusplus */ +#endif /* _AB8500_CODEC_H_ */ +/* End of file ab8500_codec.h*/ diff --git a/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h b/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h new file mode 100644 index 00000000000..4289dcfc0aa --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h @@ -0,0 +1,36 @@ +/* + * ab8500_gpadc.c - AB8500 GPADC Driver + * + * Copyright (C) 2010 ST-Ericsson SA + * Licensed under GPLv2. + * + * Author: Arun R Murthy <arun.murthy@stericsson.com> + */ + +#ifndef _AB8500_GPADC_H +#define _Ab8500_GPADC_H + +/* GPADC source: From datasheer(ADCSwSel[4:0] in GPADCCtrl2) */ +#define BAT_CTRL 0x01 +#define ACC_DETECT1 0x04 +#define ACC_DETECT2 0x05 +#define MAIN_BAT_V 0x08 +#define BK_BAT_V 0x0C +#define VBUS_V 0x09 +#define MAIN_CHARGER_V 0x03 +#define MAIN_CHARGER_C 0x0A +#define USB_CHARGER_C 0x0B +#define DIE_TEMP 0x0D +#define BTEMP_BALL 0x02 + +struct ab8500_gpadc_device_info { + struct completion ab8500_gpadc_complete; + struct mutex ab8500_gpadc_lock; +#if defined(CONFIG_REGULATOR) + struct regulator *regu; +#endif +}; + +int ab8500_gpadc_conversion(int input); + +#endif /* _AB8500_GPADC_H */ diff --git a/arch/arm/mach-ux500/include/mach/crypto-ux500.h b/arch/arm/mach-ux500/include/mach/crypto-ux500.h new file mode 100644 index 00000000000..57da88398d5 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/crypto-ux500.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _CRYPTO_UX500_H +#include <plat/ste_dma40.h> +#include <mach/ste-dma40-db8500.h> + +struct cryp_platform_data { + struct stedma40_chan_cfg mem_to_engine; + struct stedma40_chan_cfg engine_to_mem; +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/db5500-keypad.h b/arch/arm/mach-ux500/include/mach/db5500-keypad.h new file mode 100644 index 00000000000..66b4c07f838 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/db5500-keypad.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License, version 2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + */ + +#ifndef __DB5500_KEYPAD_H +#define __DB5500_KEYPAD_H + +#include <linux/input/matrix_keypad.h> + +/** + * struct db5500_keypad_platform_data - structure for platform specific data + * @keymap_data: matrix scan code table for keycodes + * @debounce_ms: platform specific debounce time + * @no_autorepeat: flag for auto repetition + */ +struct db5500_keypad_platform_data { + const struct matrix_keymap_data *keymap_data; + u8 debounce_ms; + bool no_autorepeat; +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h index 545c80fc802..6ad98329410 100644 --- a/arch/arm/mach-ux500/include/mach/db5500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db5500-regs.h @@ -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) @@ -100,4 +105,33 @@ #define U5500_GPIOBANK6_BASE (U5500_GPIO4_BASE + 0x80) #define U5500_GPIOBANK7_BASE (U5500_GPIO4_BASE + 0x100) +#define U5500_MBOX_BASE (U5500_MODEM_BASE + 0xFFD1000) +#define U5500_MBOX0_PEER_START (U5500_MBOX_BASE + 0x40) +#define U5500_MBOX0_PEER_END (U5500_MBOX_BASE + 0x5F) +#define U5500_MBOX0_LOCAL_START (U5500_MBOX_BASE + 0x60) +#define U5500_MBOX0_LOCAL_END (U5500_MBOX_BASE + 0x7F) +#define U5500_MBOX1_PEER_START (U5500_MBOX_BASE + 0x80) +#define U5500_MBOX1_PEER_END (U5500_MBOX_BASE + 0x9F) +#define U5500_MBOX1_LOCAL_START (U5500_MBOX_BASE + 0xA0) +#define U5500_MBOX1_LOCAL_END (U5500_MBOX_BASE + 0xBF) +#define U5500_MBOX2_PEER_START (U5500_MBOX_BASE + 0x00) +#define U5500_MBOX2_PEER_END (U5500_MBOX_BASE + 0x1F) +#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 diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h index 85fc6a80b38..dc70e408459 100644 --- a/arch/arm/mach-ux500/include/mach/db8500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h @@ -15,9 +15,14 @@ #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 LCLA and LCPA */ -#define U8500_DMA_LCLA_BASE U8500_ESRAM_BANK4 -#define U8500_DMA_LCPA_BASE (U8500_ESRAM_BANK4 + 0x4000) +/* + * 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 #define U8500_STM_BASE 0x80100000 @@ -27,11 +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 0xff4 offset within this region */ -#define U8500_ASIC_ID_BASE 0x9001F000 +/* 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 @@ -72,13 +78,15 @@ /* per6 base addressess */ #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 addressess */ @@ -94,7 +102,9 @@ #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) #define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) -#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x0f000) +#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) @@ -125,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) @@ -144,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 diff --git a/arch/arm/mach-ux500/include/mach/dcache.h b/arch/arm/mach-ux500/include/mach/dcache.h new file mode 100644 index 00000000000..83fe618b04f --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/dcache.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Data cache helpers + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _MACH_UX500_DCACHE_H_ +#define _MACH_UX500_DCACHE_H_ + +#include <linux/types.h> + +void drain_cpu_write_buf(void); +void clean_cpu_dcache(void *vaddr, u32 paddr, u32 length, bool inner_only, + bool *cleaned_everything); +void flush_cpu_dcache(void *vaddr, u32 paddr, u32 length, bool inner_only, + bool *flushed_everything); +bool speculative_data_prefetch(void); +/* Returns 1 if no cache is present */ +u32 get_dcache_granularity(void); + +#endif /* _MACH_UX500_DCACHE_H_ */ diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S index c5203b7ea55..058498a5ae7 100644 --- a/arch/arm/mach-ux500/include/mach/debug-macro.S +++ b/arch/arm/mach-ux500/include/mach/debug-macro.S @@ -10,19 +10,17 @@ */ #include <mach/hardware.h> -#if CONFIG_UX500_DEBUG_UART > 2 -#error Invalid Ux500 debug UART +#ifdef CONFIG_UX500_SOC_DB5500 +#define UX500_DEBUG_UART U5500_UART0_BASE +#else +#define UX500_DEBUG_UART U8500_UART2_BASE #endif -#define __UX500_UART(n) UX500_UART##n##_BASE -#define UX500_UART(n) __UX500_UART(n) -#define UART_BASE UX500_UART(CONFIG_UX500_DEBUG_UART) - .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? - ldreq \rx, =UART_BASE @ no, physical address - ldrne \rx, =IO_ADDRESS(UART_BASE) @ yes, virtual address + ldreq \rx, =UX500_DEBUG_UART @ no, physical address + ldrne \rx, =IO_ADDRESS(UX500_DEBUG_UART) @ yes, virtual address .endm #include <asm/hardware/debug-pl01x.S> diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index c2b2f257494..bf088670bbc 100644 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h @@ -13,20 +13,38 @@ struct amba_device; extern struct platform_device u5500_gpio_devs[]; extern struct platform_device u8500_gpio_devs[]; -extern struct amba_device ux500_pl031_device; -extern struct amba_device u8500_ssp0_device; -extern struct amba_device ux500_uart0_device; -extern struct amba_device ux500_uart1_device; -extern struct amba_device ux500_uart2_device; - -extern struct platform_device ux500_i2c1_device; -extern struct platform_device ux500_i2c2_device; -extern struct platform_device ux500_i2c3_device; - -extern struct platform_device u8500_i2c0_device; -extern struct platform_device u8500_i2c4_device; -extern struct platform_device u8500_dma40_device; +extern struct platform_device ux500_mcde_device; +extern struct platform_device u8500_shrm_device; +extern struct platform_device ux500_b2r2_device; +extern struct platform_device u8500_trace_modem; +extern struct platform_device u8500_pmem_device; +extern struct platform_device u8500_pmem_mio_device; +extern struct platform_device u8500_pmem_hwb_device; +extern struct platform_device ux500_hwmem_device; +extern struct platform_device ux500_dma_device; +extern struct platform_device ux500_hash1_device; +extern struct platform_device ux500_cryp1_device; +extern struct platform_device ux500_musb_device; +extern struct platform_device u5500_pwm0_device; +extern struct platform_device u5500_pwm1_device; +extern struct platform_device u5500_pwm2_device; +extern struct platform_device u5500_pwm3_device; +extern struct platform_device ux500_wdt_device; +extern struct platform_device mloader_fw_device; +extern struct platform_device u8500_thsens_device; +extern struct platform_device ux500_stm_device; +extern struct platform_device ux500_mmio_device; +extern struct platform_device u8500_hsi_device; +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) + +/** + * Touchpanel related macros declaration + */ +#define TOUCH_GPIO_PIN 84 -void dma40_u8500ed_fixup(void); +#define TOUCH_XMAX 384 +#define TOUCH_YMAX 704 +#define PRCMU_CLOCK_OCR 0x1CC +#define TSC_EXT_CLOCK_9_6MHZ 0x840000 #endif diff --git a/arch/arm/mach-ux500/include/mach/entry-macro.S b/arch/arm/mach-ux500/include/mach/entry-macro.S index 60ea88db828..15baa203889 100644 --- a/arch/arm/mach-ux500/include/mach/entry-macro.S +++ b/arch/arm/mach-ux500/include/mach/entry-macro.S @@ -17,7 +17,8 @@ .endm .macro get_irqnr_preamble, base, tmp - ldr \base, =IO_ADDRESS(UX500_GIC_CPU_BASE) + ldr \base, =gic_cpu_base_addr + ldr \base, [\base] .endm .macro arch_ret_to_user, tmp1, tmp2 diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h index d548a622e7d..25bbd61ced6 100644 --- a/arch/arm/mach-ux500/include/mach/gpio.h +++ b/arch/arm/mach-ux500/include/mach/gpio.h @@ -9,42 +9,171 @@ #include <plat/gpio.h> -#define __GPIO_RESOURCE(soc, block) \ - { \ - .start = soc##_GPIOBANK##block##_BASE, \ - .end = soc##_GPIOBANK##block##_BASE + 127, \ - .flags = IORESOURCE_MEM, \ - }, \ - { \ - .start = IRQ_GPIO##block, \ - .end = IRQ_GPIO##block, \ - .flags = IORESOURCE_IRQ, \ - } - -#define __GPIO_DEVICE(soc, block) \ - { \ - .name = "gpio", \ - .id = block, \ - .num_resources = 2, \ - .resource = &soc##_gpio_resources[block * 2], \ - .dev = { \ - .platform_data = &soc##_gpio_data[block], \ - }, \ - } - -#define GPIO_DATA(_name, first) \ - { \ - .name = _name, \ - .first_gpio = first, \ - .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ - } - -#ifdef CONFIG_UX500_SOC_DB8500 -#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U8500, block) -#define GPIO_DEVICE(block) __GPIO_DEVICE(u8500, block) -#elif defined(CONFIG_UX500_SOC_DB5500) -#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U5500, block) -#define GPIO_DEVICE(block) __GPIO_DEVICE(u5500, block) +/* Used by test applications */ +#define GPIO_TOTAL_PINS 267 + +#include <mach/hardware.h> +#include <mach/irqs.h> + +#define gpio_to_irq __gpio_to_irq + +static inline int irq_to_gpio(unsigned int irq) +{ + if (irq < NR_IRQS) + return IRQ_TO_GPIO(irq); + else + return -EINVAL; +} + +enum { + EGPIO_PIN_0 = U8500_NR_GPIO, + EGPIO_PIN_1, + EGPIO_PIN_2, + EGPIO_PIN_3, + EGPIO_PIN_4, + EGPIO_PIN_5, + EGPIO_PIN_6, + EGPIO_PIN_7, + EGPIO_PIN_8, + EGPIO_PIN_9, + EGPIO_PIN_10, + EGPIO_PIN_11, + EGPIO_PIN_12, + EGPIO_PIN_13, + EGPIO_PIN_14, + EGPIO_PIN_15, + EGPIO_PIN_16, + EGPIO_PIN_17, + EGPIO_PIN_18, + EGPIO_PIN_19, + EGPIO_PIN_20, + EGPIO_PIN_21, + EGPIO_PIN_22, + EGPIO_PIN_23, +#ifdef CONFIG_AB8500_GPIO + AB8500_PIN_GPIO1, + AB8500_PIN_GPIO2, + AB8500_PIN_GPIO3, + AB8500_PIN_GPIO4, + AB8500_PIN_GPIO5, + AB8500_PIN_GPIO6, + AB8500_PIN_GPIO7, + AB8500_PIN_GPIO8, + AB8500_PIN_GPIO9, + AB8500_PIN_GPIO10, + AB8500_PIN_GPIO11, + AB8500_PIN_GPIO12, + AB8500_PIN_GPIO13, + AB8500_PIN_GPIO14, + AB8500_PIN_GPIO15, + AB8500_PIN_GPIO16, + AB8500_PIN_GPIO17, + AB8500_PIN_GPIO18, + AB8500_PIN_GPIO19, + AB8500_PIN_GPIO20, + AB8500_PIN_GPIO21, + AB8500_PIN_GPIO22, + AB8500_PIN_GPIO23, + AB8500_PIN_GPIO24, + AB8500_PIN_GPIO25, + AB8500_PIN_GPIO26, + AB8500_PIN_GPIO27, + AB8500_PIN_GPIO28, + AB8500_PIN_GPIO29, + AB8500_PIN_GPIO30, + AB8500_PIN_GPIO31, + AB8500_PIN_GPIO32, + AB8500_PIN_GPIO33, + AB8500_PIN_GPIO34, + AB8500_PIN_GPIO35, + AB8500_PIN_GPIO36, + AB8500_PIN_GPIO37, + AB8500_PIN_GPIO38, + AB8500_PIN_GPIO39, + AB8500_PIN_GPIO40, + AB8500_PIN_GPIO41, + AB8500_PIN_GPIO42, #endif +}; + +/* Don't use in new code -- use the plain numbers */ +#define GPIO_LOW 0 +#define GPIO_HIGH 1 +#define GPIO_DATA_LOW 0 +#define GPIO_DATA_HIGH 1 +#define GPIO(x) (x) + +/* + * Alternate Function: + * refered in altfun_table to pointout particular altfun to be enabled + * when using GPIO_ALT_FUNCTION A/B/C enable/disable operation + */ +typedef enum { + GPIO_ALT_I2C_0, + GPIO_ALT_I2C_1, + GPIO_ALT_I2C_2, + GPIO_ALT_I2C_3, + GPIO_ALT_I2C_4, + GPIO_ALT_MSP_0, + GPIO_ALT_MSP_1, + GPIO_ALT_MSP_2, + GPIO_ALT_MSP_3, + GPIO_ALT_MM_CARD, + GPIO_ALT_SD_CARD, + GPIO_ALT_DMA_0, + GPIO_ALT_DMA_1, + GPIO_ALT_HSIR, + GPIO_ALT_CCIR656_INPUT, + GPIO_ALT_CCIR656_OUTPUT, + GPIO_ALT_LCD_PANELA, + GPIO_ALT_LCD_PANELB_ED, + GPIO_ALT_LCD_PANELB, + GPIO_ALT_MDIF, + GPIO_ALT_SDRAM, + GPIO_ALT_HAMAC_AUDIO_DBG, + GPIO_ALT_HAMAC_VIDEO_DBG, + GPIO_ALT_CLOCK_RESET, + GPIO_ALT_TSP, + GPIO_ALT_IRDA, + GPIO_ALT_USB_MINIMUM, + GPIO_ALT_USB_I2C, + GPIO_ALT_OWM, + GPIO_ALT_PWL, + GPIO_ALT_FSMC, + GPIO_ALT_COMP_FLASH, + GPIO_ALT_SRAM_NOR_FLASH, + GPIO_ALT_FSMC_ADDLINE_0_TO_15, + GPIO_ALT_SCROLL_KEY, + GPIO_ALT_MSHC, + GPIO_ALT_HPI, + GPIO_ALT_USB_OTG, + GPIO_ALT_SDIO, + GPIO_ALT_HSMMC, + GPIO_ALT_FSMC_ADD_DATA_0_TO_25, + GPIO_ALT_HSIT, + GPIO_ALT_NOR, + GPIO_ALT_NAND, + GPIO_ALT_KEYPAD, + GPIO_ALT_VPIP, + GPIO_ALT_CAM, + GPIO_ALT_CCP1, + GPIO_ALT_EMMC, + GPIO_ALT_SDMMC, + GPIO_ALT_TRACE, + GPIO_ALT_MMIO_INIT_BOARD, + GPIO_ALT_MMIO_CAM_SET_I2C, + GPIO_ALT_MMIO_CAM_SET_EXT_CLK, + GPIO_ALT_TRACE_MIPI60, + GPIO_ALT_SDMMC2, + GPIO_ALT_TP_SET_EXT_CLK, + GPIO_ALT_LCD_D_8, + GPIO_ALT_LCD_D_16, + GPIO_ALT_LCD_D_18, + GPIO_ALT_LCD_D_24, + GPIO_ALT_LCDA, + GPIO_ALT_LCDA_CLK, + GPIO_ALT_LCDB, + GPIO_ALT_FUNMAX /* Add new alt func before this */ +} gpio_alt_function; -#endif /* __ASM_ARCH_GPIO_H */ +#endif /* __MACH_GPIO_H */ diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h index 8656379a830..7bb75c7838e 100644 --- a/arch/arm/mach-ux500/include/mach/hardware.h +++ b/arch/arm/mach-ux500/include/mach/hardware.h @@ -29,72 +29,90 @@ #include <mach/db8500-regs.h> #include <mach/db5500-regs.h> -#ifdef CONFIG_UX500_SOC_DB8500 -#define UX500(periph) U8500_##periph##_BASE -#elif defined(CONFIG_UX500_SOC_DB5500) -#define UX500(periph) U5500_##periph##_BASE -#endif - -#define UX500_BACKUPRAM0_BASE UX500(BACKUPRAM0) -#define UX500_BACKUPRAM1_BASE UX500(BACKUPRAM1) -#define UX500_B2R2_BASE UX500(B2R2) - -#define UX500_CLKRST1_BASE UX500(CLKRST1) -#define UX500_CLKRST2_BASE UX500(CLKRST2) -#define UX500_CLKRST3_BASE UX500(CLKRST3) -#define UX500_CLKRST5_BASE UX500(CLKRST5) -#define UX500_CLKRST6_BASE UX500(CLKRST6) - -#define UX500_DMA_BASE UX500(DMA) -#define UX500_FSMC_BASE UX500(FSMC) - -#define UX500_GIC_CPU_BASE UX500(GIC_CPU) -#define UX500_GIC_DIST_BASE UX500(GIC_DIST) - -#define UX500_I2C1_BASE UX500(I2C1) -#define UX500_I2C2_BASE UX500(I2C2) -#define UX500_I2C3_BASE UX500(I2C3) - -#define UX500_L2CC_BASE UX500(L2CC) -#define UX500_MCDE_BASE UX500(MCDE) -#define UX500_MTU0_BASE UX500(MTU0) -#define UX500_MTU1_BASE UX500(MTU1) -#define UX500_PRCMU_BASE UX500(PRCMU) - -#define UX500_RNG_BASE UX500(RNG) -#define UX500_RTC_BASE UX500(RTC) - -#define UX500_SCU_BASE UX500(SCU) - -#define UX500_SDI0_BASE UX500(SDI0) -#define UX500_SDI1_BASE UX500(SDI1) -#define UX500_SDI2_BASE UX500(SDI2) -#define UX500_SDI3_BASE UX500(SDI3) -#define UX500_SDI4_BASE UX500(SDI4) +/* ST-Ericsson modified pl022 id */ +#define SSP_PER_ID 0x01080022 +#define SSP_PER_MASK 0x0fffffff -#define UX500_SPI0_BASE UX500(SPI0) -#define UX500_SPI1_BASE UX500(SPI1) -#define UX500_SPI2_BASE UX500(SPI2) -#define UX500_SPI3_BASE UX500(SPI3) +/* SSP specific declaration */ +#define SPI_PER_ID 0x00080023 +#define SPI_PER_MASK 0x0fffffff -#define UX500_SIA_BASE UX500(SIA) -#define UX500_SVA_BASE UX500(SVA) +/* MSP specific declaration */ +#define MSP_PER_ID 0x00280021 +#define MSP_PER_MASK 0x00ffffff -#define UX500_TWD_BASE UX500(TWD) +/* DMA specific declaration */ +#define DMA_PER_ID 0x8A280080 +#define DMA_PER_MASK 0xffffffff -#define UX500_UART0_BASE UX500(UART0) -#define UX500_UART1_BASE UX500(UART1) -#define UX500_UART2_BASE UX500(UART2) +#define GPIO_PER_ID 0x1f380060 +#define GPIO_PER_MASK 0xffffffff -#define UX500_USBOTG_BASE UX500(USBOTG) +/* RTC specific declaration */ +#define RTC_PER_ID 0x00280031 +#define RTC_PER_MASK 0x00ffffff -/* ST-Ericsson modified pl022 id */ -#define SSP_PER_ID 0x01080022 +/* + * FIFO offsets for IPs + */ +#define I2C_TX_REG_OFFSET (0x10) +#define I2C_RX_REG_OFFSET (0x18) +#define UART_TX_RX_REG_OFFSET (0) +#define MSP_TX_RX_REG_OFFSET (0) +#define SSP_TX_RX_REG_OFFSET (0x8) +#define SPI_TX_RX_REG_OFFSET (0x8) +#define SD_MMC_TX_RX_REG_OFFSET (0x80) +#define CRYP1_RX_REG_OFFSET (0x10) +#define CRYP1_TX_REG_OFFSET (0x8) + +#define MSP_0_CONTROLLER 1 +#define MSP_1_CONTROLLER 2 +#define MSP_2_CONTROLLER 3 +#define MSP_3_CONTROLLER 4 + +#define SSP_0_CONTROLLER 4 +#define SSP_1_CONTROLLER 5 + +#define SPI023_0_CONTROLLER 6 +#define SPI023_1_CONTROLLER 7 +#define SPI023_2_CONTROLLER 8 +#define SPI023_3_CONTROLLER 9 + +/* MSP related board specific declaration************************/ + +#define MSP_DATA_DELAY MSP_DELAY_0 +#define MSP_TX_CLOCK_EDGE MSP_FALLING_EDGE +#define MSP_RX_CLOCK_EDGE MSP_FALLING_EDGE +#define NUM_MSP_CONTROLLER 3 + +/* I2C configuration + * * * + * * */ +#define I2C0_LP_OWNADDR 0x31 +#define I2C1_LP_OWNADDR 0x60 +#define I2C2_LP_OWNADDR 0x70 +#define I2C3_LP_OWNADDR 0x80 +#define I2C4_LP_OWNADDR 0x90 + +/* SDMMC specific declarations */ +#define SDI_PER_ID 0x00480180 +#define SDI_PER_MASK 0x00ffffff +/* B2R2 clock management register */ +#define PRCM_B2R2CLK_MGT_REG 0x80157078 /** B2R2 clock selection */ #ifndef __ASSEMBLY__ +extern void __iomem *_PRCMU_BASE; + #include <asm/cputype.h> +#include <asm/mach-types.h> +static inline bool ux500_is_svp(void) +{ + return machine_is_svp8500v1() || + machine_is_svp8500v2() || + machine_is_svp5500(); +} static inline bool cpu_is_u8500(void) { #ifdef CONFIG_UX500_SOC_DB8500 @@ -104,16 +122,56 @@ static inline bool cpu_is_u8500(void) #endif } +#define CPUID_DB8500ED 0x410fc090 +#define CPUID_DB8500V1 0x411fc091 +#define CPUID_DB8500V2 0x412fc091 + static inline bool cpu_is_u8500ed(void) { - return cpu_is_u8500() && (read_cpuid_id() & 15) == 0; + /* + * SVP8500 unfortunately does not update the MIDR register on silicon + * revisions, but instead maintains the old ED value. + */ + if (ux500_is_svp()) + return false; + + return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED); } static inline bool cpu_is_u8500v1(void) { - return cpu_is_u8500() && (read_cpuid_id() & 15) == 1; + if (machine_is_svp8500v1()) + return true; + else if (machine_is_svp8500v2()) + return false; + + return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1); +} + +static inline bool cpu_is_u8500v2(void) +{ + if (machine_is_svp8500v1()) + return false; + else if (machine_is_svp8500v2()) + return true; + + return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2); } +#ifdef CONFIG_UX500_SOC_DB8500 +bool cpu_is_u8500v10(void); +bool cpu_is_u8500v11(void); +bool cpu_is_u8500v20(void); +bool cpu_is_u8500v21(void); +bool cpu_is_u8500v20_or_later(void); +#else +static inline bool cpu_is_u8500v10(void) { return false; } +static inline bool cpu_is_u8500v11(void) { return false; } +static inline bool cpu_is_u8500v20(void) { return false; } +static inline bool cpu_is_u8500v21(void) { return false; } +static inline bool cpu_is_u8500v20_or_later(void) { return false; } +#endif + static inline bool cpu_is_u5500(void) { #ifdef CONFIG_UX500_SOC_DB5500 @@ -125,4 +183,7 @@ static inline bool cpu_is_u5500(void) #endif +/* Keep this greppable for SoC porters */ +#define ux500_unknown_soc() BUG() + #endif /* __MACH_HARDWARE_H */ diff --git a/arch/arm/mach-ux500/include/mach/hcl_defs.h b/arch/arm/mach-ux500/include/mach/hcl_defs.h new file mode 100644 index 00000000000..efd37608cb3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/hcl_defs.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _HCL_DEFS_H +#define _HCL_DEFS_H +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +//#include "platform_os.h" + +/*----------------------------------------------------------------------------- + * Type definition + *---------------------------------------------------------------------------*/ +typedef unsigned char t_uint8; +typedef signed char t_sint8; +typedef unsigned short t_uint16; +typedef signed short t_sint16; +typedef unsigned long t_uint32; +typedef signed long t_sint32; + +typedef unsigned int t_bitfield; + + + +#if !defined(FALSE) && !defined(TRUE) +typedef int t_bool; +#define FALSE 0 +#define TRUE 1 +#endif + +/* + * Definition of the different kind of addresses manipulated into a system with MMU + * (handle physical AND logical addresses) + */ + + +typedef t_uint32 t_physical_address; +typedef t_uint32 t_logical_address; + + + +/* + * Global frequency enumuration + * Added to avoid frequency conversion function which is required to convert one HCL + * frequency enumuration values to another HCL frequency enumuration values. + */ + +/*typedef enum { + HCL_FREQ_NOT_SUPPORTED=-1, + HCL_FREQ_8KHZ , + HCL_FREQ_11_25KHZ, + HCL_FREQ_12KHZ, + HCL_FREQ_16KHZ, + HCL_FREQ_22_05KHZ, + HCL_FREQ_22_5KHZ, + HCL_FREQ_24KHZ, + HCL_FREQ_32KHZ, + HCL_FREQ_44KHZ, + HCL_FREQ_44_1KHZ, + HCL_FREQ_48KHZ, + HCL_FREQ_64KHZ, + HCL_FREQ_88KHZ, + HCL_FREQ_88_2KHZ, + HCL_FREQ_96KHZ, + HCL_FREQ_128KHZ, + HCL_FREQ_176_4KHZ, + HCL_FREQ_192KHZ, + + HCL_FREQ_1MHZ, + HCL_FREQ_2MHZ, + HCL_FREQ_3MHZ, + HCL_FREQ_4MHZ, + HCL_FREQ_5MHZ, + HCL_FREQ_6MHZ, + HCL_FREQ_8MHZ, + HCL_FREQ_11MHZ, + HCL_FREQ_12MHZ, + HCL_FREQ_16MHZ, + HCL_FREQ_22MHZ, + HCL_FREQ_24MHZ, + HCL_FREQ_48MHZ +} t_frequency; + +*/ + +typedef struct { + t_physical_address physical; + t_logical_address logical; +} t_system_address; + + +/* + * Define a type used to manipulate size of various buffers + */ +typedef t_uint32 t_size; + +typedef struct { + t_bitfield minor:8; + t_bitfield major:8; + t_bitfield version:16; +} t_version; + + + + +/*----------------------------------------------------------------------------- + * Keyword definition + *---------------------------------------------------------------------------*/ +#define PUBLIC /* Extern by default */ +#define PRIVATE static + +#ifndef NULL +#define NULL (0) +#endif /* ndef NULL */ + + +/*----------------------------------------------------------------------------- + * Bit setting or clearing + *---------------------------------------------------------------------------*/ +#define HCL_SET_BITS(reg,mask) ((reg) |= (mask)) +#define HCL_CLEAR_BITS(reg,mask) ((reg) &= ~(mask)) +#define HCL_READ_BITS(reg,mask) ((reg) & (mask)) +#define HCL_WRITE_BITS(reg,val,mask) ((reg) = (((reg) & ~(mask)) | ((val) & (mask)))) +#define HCL_READ_REG(reg) (reg) +#define HCL_WRITE_REG(reg,val) ((reg) = (val)) + +/*----------------------------------------------------------------------------- + * field offset extraction from a structure + *---------------------------------------------------------------------------*/ +#define HCL_BITFIELD_OFFSET(typeName, fieldName) (t_uint32)(&(((typeName *)0)->fieldName)) + +/*----------------------------------------------------------------------------- + * Bit mask definition + *---------------------------------------------------------------------------*/ +#define MASK_NULL8 0x00 +#define MASK_NULL16 0x0000 +#define MASK_NULL32 0x00000000 +#define MASK_ALL8 0xFF +#define MASK_ALL16 0xFFFF +#define MASK_ALL32 0xFFFFFFFF + +#define MASK_BIT0 (1UL<<0) +#define MASK_BIT1 (1UL<<1) +#define MASK_BIT2 (1UL<<2) +#define MASK_BIT3 (1UL<<3) +#define MASK_BIT4 (1UL<<4) +#define MASK_BIT5 (1UL<<5) +#define MASK_BIT6 (1UL<<6) +#define MASK_BIT7 (1UL<<7) +#define MASK_BIT8 (1UL<<8) +#define MASK_BIT9 (1UL<<9) +#define MASK_BIT10 (1UL<<10) +#define MASK_BIT11 (1UL<<11) +#define MASK_BIT12 (1UL<<12) +#define MASK_BIT13 (1UL<<13) +#define MASK_BIT14 (1UL<<14) +#define MASK_BIT15 (1UL<<15) +#define MASK_BIT16 (1UL<<16) +#define MASK_BIT17 (1UL<<17) +#define MASK_BIT18 (1UL<<18) +#define MASK_BIT19 (1UL<<19) +#define MASK_BIT20 (1UL<<20) +#define MASK_BIT21 (1UL<<21) +#define MASK_BIT22 (1UL<<22) +#define MASK_BIT23 (1UL<<23) +#define MASK_BIT24 (1UL<<24) +#define MASK_BIT25 (1UL<<25) +#define MASK_BIT26 (1UL<<26) +#define MASK_BIT27 (1UL<<27) +#define MASK_BIT28 (1UL<<28) +#define MASK_BIT29 (1UL<<29) +#define MASK_BIT30 (1UL<<30) +#define MASK_BIT31 (1UL<<31) + +/*----------------------------------------------------------------------------- + * quartet shift definition + *---------------------------------------------------------------------------*/ +#define MASK_QUARTET (0xFUL) +#define SHIFT_QUARTET0 0 +#define SHIFT_QUARTET1 4 +#define SHIFT_QUARTET2 8 +#define SHIFT_QUARTET3 12 +#define SHIFT_QUARTET4 16 +#define SHIFT_QUARTET5 20 +#define SHIFT_QUARTET6 24 +#define SHIFT_QUARTET7 28 +#define MASK_QUARTET0 (MASK_QUARTET << SHIFT_QUARTET0) +#define MASK_QUARTET1 (MASK_QUARTET << SHIFT_QUARTET1) +#define MASK_QUARTET2 (MASK_QUARTET << SHIFT_QUARTET2) +#define MASK_QUARTET3 (MASK_QUARTET << SHIFT_QUARTET3) +#define MASK_QUARTET4 (MASK_QUARTET << SHIFT_QUARTET4) +#define MASK_QUARTET5 (MASK_QUARTET << SHIFT_QUARTET5) +#define MASK_QUARTET6 (MASK_QUARTET << SHIFT_QUARTET6) +#define MASK_QUARTET7 (MASK_QUARTET << SHIFT_QUARTET7) + +/*----------------------------------------------------------------------------- + * Byte shift definition + *---------------------------------------------------------------------------*/ +#define MASK_BYTE (0xFFUL) +#define SHIFT_BYTE0 0 +#define SHIFT_BYTE1 8 +#define SHIFT_BYTE2 16 +#define SHIFT_BYTE3 24 +#define MASK_BYTE0 (MASK_BYTE << SHIFT_BYTE0) +#define MASK_BYTE1 (MASK_BYTE << SHIFT_BYTE1) +#define MASK_BYTE2 (MASK_BYTE << SHIFT_BYTE2) +#define MASK_BYTE3 (MASK_BYTE << SHIFT_BYTE3) + +/*----------------------------------------------------------------------------- + * Halfword shift definition + *---------------------------------------------------------------------------*/ +#define MASK_HALFWORD (0xFFFFUL) +#define SHIFT_HALFWORD0 0 +#define SHIFT_HALFWORD1 16 +#define MASK_HALFWORD0 (MASK_HALFWORD << SHIFT_HALFWORD0) +#define MASK_HALFWORD1 (MASK_HALFWORD << SHIFT_HALFWORD1) + +/*----------------------------------------------------------------------------- + * Global constants definition + *---------------------------------------------------------------------------*/ + #define ONE_KB (1024) + #define ONE_MB (ONE_KB * ONE_KB) + + +/*----------------------------------------------------------------------------- + * Address translation macros declaration + *---------------------------------------------------------------------------*/ + +#define ARM_TO_AHB_ADDR(addr) (addr) +#define AHB_TO_ARM_ADDR(addr) (addr) + +/* For input parameters - would not be changed by the API */ +#define IN +/* For output parameters - would be changes by the API */ +#define OUT +/* For input-output parameters - provides input to the API but would be changed by the API */ +#define INOUT +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HCL_DEFS_H */ + +/* End of file hcl_defs.h */ + + diff --git a/arch/arm/mach-ux500/include/mach/hsi.h b/arch/arm/mach-ux500/include/mach/hsi.h new file mode 100644 index 00000000000..030e35e729b --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/hsi.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + */ + +#ifndef __MACH_HSI_H +#define __MACH_HSI_H + +#include <plat/ste_dma40.h> + +/* HSIT register offsets */ +#define STE_HSI_TX_ID 0x000 +#define STE_HSI_TX_MODE 0x004 +#define STE_HSI_TX_STATE 0x008 +#define STE_HSI_TX_IOSTATE 0x00C +#define STE_HSI_TX_BUFSTATE 0x010 +#define STE_HSI_TX_DIVISOR 0x014 +#define STE_HSI_TX_PARITY 0x018 +#define STE_HSI_TX_BREAK 0x01C +#define STE_HSI_TX_CHANNELS 0x020 +#define STE_HSI_TX_FLUSHBITS 0x024 +#define STE_HSI_TX_PRIORITY 0x028 +#define STE_HSI_TX_BURSTLEN 0x02C +#define STE_HSI_TX_PREAMBLE 0x030 +#define STE_HSI_TX_DATASWAP 0x034 +#define STE_HSI_TX_FRAMELENX 0x080 +#define STE_HSI_TX_BUFFERX 0x0C0 +#define STE_HSI_TX_BASEX 0x100 +#define STE_HSI_TX_SPANX 0x140 +#define STE_HSI_TX_GAUGEX 0x180 +#define STE_HSI_TX_WATERMARKX 0x1C0 +#define STE_HSI_TX_DMAEN 0x200 +#define STE_HSI_TX_WATERMARKIS 0x204 +#define STE_HSI_TX_WATERMARKIM 0x208 +#define STE_HSI_TX_WATERMARKIC 0x20C +#define STE_HSI_TX_WATERMARKID 0x210 +#define STE_HSI_TX_PERIPHID0 0xFE0 +#define STE_HSI_TX_PERIPHID1 0xFE4 +#define STE_HSI_TX_PERIPHID2 0xFE8 +#define STE_HSI_TX_PERIPHID3 0xFEC + +/* HSIR register offsets */ +#define STE_HSI_RX_ID 0x000 +#define STE_HSI_RX_MODE 0x004 +#define STE_HSI_RX_STATE 0x008 +#define STE_HSI_RX_BUFSTATE 0x00C +#define STE_HSI_RX_THRESHOLD 0x010 +#define STE_HSI_RX_PARITY 0x014 +#define STE_HSI_RX_DETECTOR 0x018 +#define STE_HSI_RX_EXCEP 0x01C +#define STE_HSI_RX_ACK 0x020 +#define STE_HSI_RX_CHANNELS 0x024 +#define STE_HSI_RX_REALTIME 0x028 +#define STE_HSI_RX_OVERRUN 0x02C +#define STE_HSI_RX_OVERRUNACK 0x030 +#define STE_HSI_RX_PREAMBLE 0x034 +#define STE_HSI_RX_PIPEGAUGE 0x038 +#define STE_HSI_RX_STATICCONFID 0x03C +#define STE_HSI_RX_BUFFERX 0x080 +#define STE_HSI_RX_FRAMELENX 0x0C0 +#define STE_HSI_RX_BASEX 0x100 +#define STE_HSI_RX_SPANX 0x140 +#define STE_HSI_RX_GAUGEX 0x180 +#define STE_HSI_RX_WATERMARKX 0x1C0 +#define STE_HSI_RX_DMAEN 0x200 +#define STE_HSI_RX_WATERMARKIS 0x204 +#define STE_HSI_RX_WATERMARKIM 0x208 +#define STE_HSI_RX_WATERMARKIC 0x20C +#define STE_HSI_RX_WATERMARKID 0x210 +#define STE_HSI_RX_OVERRUNMIS 0x214 +#define STE_HSI_RX_OVERRUNIM 0x218 +#define STE_HSI_RX_EXCEPMIS 0x21C +#define STE_HSI_RX_EXCEPIM 0x220 +#define STE_HSI_RX_PERIPHID0 0xFE0 +#define STE_HSI_RX_PERIPHID1 0xFE4 +#define STE_HSI_RX_PERIPHID2 0xFE8 +#define STE_HSI_RX_PERIPHID3 0xFEC + +/* HSI states */ +#define STE_HSI_STATE_IDLE 0x00 +#define STE_HSI_STATE_START 0x01 +#define STE_HSI_STATE_TRANSMIT 0x02 +#define STE_HSI_STATE_BREAK 0x03 +#define STE_HSI_STATE_FLUSH 0x04 +#define STE_HSI_STATE_HALT 0x05 + +/* HSI exceptions */ +#define STE_HSI_EXCEP_TIMEOUT 0x01 +#define STE_HSI_EXCEP_OVERRUN 0x02 +#define STE_HSI_EXCEP_BREAK 0x04 +#define STE_HSI_EXCEP_PARITY 0x08 + +/* HSI modes */ +#define STE_HSI_MODE_SLEEP 0x00 +#define STE_HSI_MODE_STREAM 0x01 +#define STE_HSI_MODE_FRAME 0x02 +#define STE_HSI_MODE_PIPELINED 0x03 +#define STE_HSI_MODE_FAILSAFE 0x04 + +#define STE_HSI_MAX_BUFFERS 32 + +/* Max channels of STE HSI controller */ +#define STE_HSI_MAX_CHANNELS 4 + +struct stedma40_chan_cfg; + +struct ste_hsi_port_cfg { +#ifdef CONFIG_STE_DMA40 + bool (*dma_filter)(struct dma_chan *chan, void *filter_param); + struct stedma40_chan_cfg *dma_tx_cfg; + struct stedma40_chan_cfg *dma_rx_cfg; +#endif +}; + +struct ste_hsi_platform_data { + int num_ports; + int use_dma; + struct ste_hsi_port_cfg *port_cfg; +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h new file mode 100644 index 00000000000..4aa25c31a22 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_IRQS_BOARD_MOP500_H +#define __MACH_IRQS_BOARD_MOP500_H + +#define AB8500_NR_IRQS 112 + +#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START +#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ + + AB8500_NR_IRQS) + +/* TC3589X irqs */ +#define TC35892_NR_INTERNAL_IRQS 8 +#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x)) +#define TC35892_NR_GPIOS 24 +#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS) + +#define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS + +#define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END +#define MOP500_EGPIO_IRQ(x) (MOP500_EGPIO_IRQ_BASE + (x)) +#define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \ + + MOP500_EGPIO_NR_IRQS) + +/* STMPE1601 irqs */ +#define STMPE_NR_INTERNAL_IRQS 9 +#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x)) +#define STMPE_NR_GPIOS 24 +#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS) + +#define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END +#define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) +#define MOP500_STMPE1601_IRQ_END \ + MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) + +/* AB8500 virtual gpio IRQ */ +#define AB8500_VIR_GPIO_NR_IRQS 16 + +#define MOP500_AB8500_VIR_GPIO_IRQ_BASE \ + MOP500_STMPE1601_IRQ_END +#define MOP500_AB8500_VIR_GPIO_IRQ_END \ + (MOP500_AB8500_VIR_GPIO_IRQ_BASE + AB8500_VIR_GPIO_NR_IRQS) + +#define MOP500_NR_IRQS MOP500_AB8500_VIR_GPIO_IRQ_END + +#define MOP500_IRQ_END MOP500_NR_IRQS + +#if MOP500_IRQ_END > IRQ_BOARD_END +#undef IRQ_BOARD_END +#define IRQ_BOARD_END MOP500_IRQ_END +#endif + +#endif diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h new file mode 100644 index 00000000000..48f9f382b29 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h @@ -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 (23 * 8) +#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 diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h new file mode 100644 index 00000000000..92b1fbf32bb --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/irqs-db5500.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_IRQS_DB5500_H +#define __MACH_IRQS_DB5500_H + +#define IRQ_DB5500_MTU0 (IRQ_SHPI_START + 4) +#define IRQ_DB5500_SPI2 (IRQ_SHPI_START + 6) +#define IRQ_DB5500_PMU0 (IRQ_SHPI_START + 7) +#define IRQ_DB5500_SPI0 (IRQ_SHPI_START + 8) +#define IRQ_DB5500_RTT (IRQ_SHPI_START + 9) +#define IRQ_DB5500_PKA (IRQ_SHPI_START + 10) +#define IRQ_DB5500_UART0 (IRQ_SHPI_START + 11) +#define IRQ_DB5500_I2C3 (IRQ_SHPI_START + 12) +#define IRQ_DB5500_L2CC (IRQ_SHPI_START + 13) +#define IRQ_DB5500_MSP0 (IRQ_SHPI_START + 14) +#define IRQ_DB5500_CRYP1 (IRQ_SHPI_START + 15) +#define IRQ_DB5500_PMU1 (IRQ_SHPI_START + 16) +#define IRQ_DB5500_MTU1 (IRQ_SHPI_START + 17) +#define IRQ_DB5500_RTC (IRQ_SHPI_START + 18) +#define IRQ_DB5500_UART1 (IRQ_SHPI_START + 19) +#define IRQ_DB5500_USB_WAKEUP (IRQ_SHPI_START + 20) +#define IRQ_DB5500_I2C0 (IRQ_SHPI_START + 21) +#define IRQ_DB5500_I2C1 (IRQ_SHPI_START + 22) +#define IRQ_DB5500_USBOTG (IRQ_SHPI_START + 23) +#define IRQ_DB5500_DMA_SECURE (IRQ_SHPI_START + 24) +#define IRQ_DB5500_DMA (IRQ_SHPI_START + 25) +#define IRQ_DB5500_UART2 (IRQ_SHPI_START + 26) +#define IRQ_DB5500_ICN_PMU1 (IRQ_SHPI_START + 27) +#define IRQ_DB5500_ICN_PMU2 (IRQ_SHPI_START + 28) +#define IRQ_DB5500_UART3 (IRQ_SHPI_START + 29) +#define IRQ_DB5500_SPI3 (IRQ_SHPI_START + 30) +#define IRQ_DB5500_SDMMC4 (IRQ_SHPI_START + 31) +#define IRQ_DB5500_IRRC (IRQ_SHPI_START + 33) +#define IRQ_DB5500_IRDA_FT (IRQ_SHPI_START + 34) +#define IRQ_DB5500_IRDA_SD (IRQ_SHPI_START + 35) +#define IRQ_DB5500_IRDA_FI (IRQ_SHPI_START + 36) +#define IRQ_DB5500_IRDA_FD (IRQ_SHPI_START + 37) +#define IRQ_DB5500_FSMC_CODEREADY (IRQ_SHPI_START + 38) +#define IRQ_DB5500_FSMC_NANDWAIT (IRQ_SHPI_START + 39) +#define IRQ_DB5500_AB5500 (IRQ_SHPI_START + 40) +#define IRQ_DB5500_SDMMC2 (IRQ_SHPI_START + 41) +#define IRQ_DB5500_SIA (IRQ_SHPI_START + 42) +#define IRQ_DB5500_SIA2 (IRQ_SHPI_START + 43) +#define IRQ_DB5500_HVA (IRQ_SHPI_START + 44) +#define IRQ_DB5500_HVA2 (IRQ_SHPI_START + 45) +#define IRQ_DB5500_PRCMU0 (IRQ_SHPI_START + 46) +#define IRQ_DB5500_PRCMU1 (IRQ_SHPI_START + 47) +#define IRQ_DB5500_DISP (IRQ_SHPI_START + 48) +#define IRQ_DB5500_SDMMC1 (IRQ_SHPI_START + 50) +#define IRQ_DB5500_MSP1 (IRQ_SHPI_START + 52) +#define IRQ_DB5500_KBD (IRQ_SHPI_START + 53) +#define IRQ_DB5500_I2C2 (IRQ_SHPI_START + 55) +#define IRQ_DB5500_B2R2 (IRQ_SHPI_START + 56) +#define IRQ_DB5500_CRYP0 (IRQ_SHPI_START + 57) +#define IRQ_DB5500_SDMMC3 (IRQ_SHPI_START + 59) +#define IRQ_DB5500_SDMMC0 (IRQ_SHPI_START + 60) +#define IRQ_DB5500_HSEM (IRQ_SHPI_START + 61) +#define IRQ_DB5500_SBAG (IRQ_SHPI_START + 63) +#define IRQ_DB5500_MODEM (IRQ_SHPI_START + 65) +#define IRQ_DB5500_SPI1 (IRQ_SHPI_START + 96) +#define IRQ_DB5500_MSP2 (IRQ_SHPI_START + 98) +#define IRQ_DB5500_SRPTIMER (IRQ_SHPI_START + 101) +#define IRQ_DB5500_CTI0 (IRQ_SHPI_START + 108) +#define IRQ_DB5500_CTI1 (IRQ_SHPI_START + 109) +#define IRQ_DB5500_ICN_ERR (IRQ_SHPI_START + 110) +#define IRQ_DB5500_MALI_PPMMU (IRQ_SHPI_START + 112) +#define IRQ_DB5500_MALI_PP (IRQ_SHPI_START + 113) +#define IRQ_DB5500_MALI_GPMMU (IRQ_SHPI_START + 114) +#define IRQ_DB5500_MALI_GP (IRQ_SHPI_START + 115) +#define IRQ_DB5500_MALI (IRQ_SHPI_START + 116) +#define IRQ_DB5500_PRCMU_SEM (IRQ_SHPI_START + 118) +#define IRQ_DB5500_GPIO0 (IRQ_SHPI_START + 119) +#define IRQ_DB5500_GPIO1 (IRQ_SHPI_START + 120) +#define IRQ_DB5500_GPIO2 (IRQ_SHPI_START + 121) +#define IRQ_DB5500_GPIO3 (IRQ_SHPI_START + 122) +#define IRQ_DB5500_GPIO4 (IRQ_SHPI_START + 123) +#define IRQ_DB5500_GPIO5 (IRQ_SHPI_START + 124) +#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) + +#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 diff --git a/arch/arm/mach-ux500/include/mach/irqs-db8500.h b/arch/arm/mach-ux500/include/mach/irqs-db8500.h new file mode 100644 index 00000000000..29f905fcc1e --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/irqs-db8500.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_IRQS_DB8500_H +#define __MACH_IRQS_DB8500_H + +#define IRQ_DB8500_MTU0 (IRQ_SHPI_START + 4) +#define IRQ_DB8500_SPI2 (IRQ_SHPI_START + 6) +#define IRQ_DB8500_PMU (IRQ_SHPI_START + 7) +#define IRQ_DB8500_SPI0 (IRQ_SHPI_START + 8) +#define IRQ_DB8500_RTT (IRQ_SHPI_START + 9) +#define IRQ_DB8500_PKA (IRQ_SHPI_START + 10) +#define IRQ_DB8500_UART0 (IRQ_SHPI_START + 11) +#define IRQ_DB8500_I2C3 (IRQ_SHPI_START + 12) +#define IRQ_DB8500_L2CC (IRQ_SHPI_START + 13) +#define IRQ_DB8500_SSP0 (IRQ_SHPI_START + 14) +#define IRQ_DB8500_CRYP1 (IRQ_SHPI_START + 15) +#define IRQ_DB8500_MSP1_RX (IRQ_SHPI_START + 16) +#define IRQ_DB8500_MTU1 (IRQ_SHPI_START + 17) +#define IRQ_DB8500_RTC (IRQ_SHPI_START + 18) +#define IRQ_DB8500_UART1 (IRQ_SHPI_START + 19) +#define IRQ_DB8500_USB_WAKEUP (IRQ_SHPI_START + 20) +#define IRQ_DB8500_I2C0 (IRQ_SHPI_START + 21) +#define IRQ_DB8500_I2C1 (IRQ_SHPI_START + 22) +#define IRQ_DB8500_USBOTG (IRQ_SHPI_START + 23) +#define IRQ_DB8500_DMA_SECURE (IRQ_SHPI_START + 24) +#define IRQ_DB8500_DMA (IRQ_SHPI_START + 25) +#define IRQ_DB8500_UART2 (IRQ_SHPI_START + 26) +#define IRQ_DB8500_ICN_PMU1 (IRQ_SHPI_START + 27) +#define IRQ_DB8500_ICN_PMU2 (IRQ_SHPI_START + 28) +#define IRQ_DB8500_HSIR_EXCEP (IRQ_SHPI_START + 29) +#define IRQ_DB8500_MSP0 (IRQ_SHPI_START + 31) +#define IRQ_DB8500_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32) +#define IRQ_DB8500_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33) +#define IRQ_DB8500_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34) +#define IRQ_DB8500_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35) +#define IRQ_DB8500_HSIR_CH4_OVRRUN (IRQ_SHPI_START + 36) +#define IRQ_DB8500_HSIR_CH5_OVRRUN (IRQ_SHPI_START + 37) +#define IRQ_DB8500_HSIR_CH6_OVRRUN (IRQ_SHPI_START + 38) +#define IRQ_DB8500_HSIR_CH7_OVRRUN (IRQ_SHPI_START + 39) +#define IRQ_DB8500_AB8500 (IRQ_SHPI_START + 40) +#define IRQ_DB8500_SDMMC2 (IRQ_SHPI_START + 41) +#define IRQ_DB8500_SIA (IRQ_SHPI_START + 42) +#define IRQ_DB8500_SIA2 (IRQ_SHPI_START + 43) +#define IRQ_DB8500_SVA (IRQ_SHPI_START + 44) +#define IRQ_DB8500_SVA2 (IRQ_SHPI_START + 45) +#define IRQ_DB8500_PRCMU0 (IRQ_SHPI_START + 46) +#define IRQ_DB8500_PRCMU1 (IRQ_SHPI_START + 47) +#define IRQ_DB8500_DISP (IRQ_SHPI_START + 48) +#define IRQ_DB8500_SPI3 (IRQ_SHPI_START + 49) +#define IRQ_DB8500_SDMMC1 (IRQ_SHPI_START + 50) +#define IRQ_DB8500_I2C4 (IRQ_SHPI_START + 51) +#define IRQ_DB8500_SSP1 (IRQ_SHPI_START + 52) +#define IRQ_DB8500_SKE (IRQ_SHPI_START + 53) +#define IRQ_DB8500_KB (IRQ_SHPI_START + 54) +#define IRQ_DB8500_I2C2 (IRQ_SHPI_START + 55) +#define IRQ_DB8500_B2R2 (IRQ_SHPI_START + 56) +#define IRQ_DB8500_CRYP0 (IRQ_SHPI_START + 57) +#define IRQ_DB8500_SDMMC3 (IRQ_SHPI_START + 59) +#define IRQ_DB8500_SDMMC0 (IRQ_SHPI_START + 60) +#define IRQ_DB8500_HSEM (IRQ_SHPI_START + 61) +#define IRQ_DB8500_MSP1 (IRQ_SHPI_START + 62) +#define IRQ_DB8500_SBAG (IRQ_SHPI_START + 63) +#define IRQ_DB8500_SPI1 (IRQ_SHPI_START + 96) +#define IRQ_DB8500_SRPTIMER (IRQ_SHPI_START + 97) +#define IRQ_DB8500_MSP2 (IRQ_SHPI_START + 98) +#define IRQ_DB8500_SDMMC4 (IRQ_SHPI_START + 99) +#define IRQ_DB8500_SDMMC5 (IRQ_SHPI_START + 100) +#define IRQ_DB8500_HSIRD0 (IRQ_SHPI_START + 104) +#define IRQ_DB8500_HSIRD1 (IRQ_SHPI_START + 105) +#define IRQ_DB8500_HSITD0 (IRQ_SHPI_START + 106) +#define IRQ_DB8500_HSITD1 (IRQ_SHPI_START + 107) +#define IRQ_DB8500_CTI0 (IRQ_SHPI_START + 108) +#define IRQ_DB8500_CTI1 (IRQ_SHPI_START + 109) +#define IRQ_DB8500_ICN_ERR (IRQ_SHPI_START + 110) +#define IRQ_DB8500_MALI_PPMMU (IRQ_SHPI_START + 112) +#define IRQ_DB8500_MALI_PP (IRQ_SHPI_START + 113) +#define IRQ_DB8500_MALI_GPMMU (IRQ_SHPI_START + 114) +#define IRQ_DB8500_MALI_GP (IRQ_SHPI_START + 115) +#define IRQ_DB8500_MALI (IRQ_SHPI_START + 116) +#define IRQ_DB8500_PRCMU_SEM (IRQ_SHPI_START + 118) +#define IRQ_DB8500_GPIO0 (IRQ_SHPI_START + 119) +#define IRQ_DB8500_GPIO1 (IRQ_SHPI_START + 120) +#define IRQ_DB8500_GPIO2 (IRQ_SHPI_START + 121) +#define IRQ_DB8500_GPIO3 (IRQ_SHPI_START + 122) +#define IRQ_DB8500_GPIO4 (IRQ_SHPI_START + 123) +#define IRQ_DB8500_GPIO5 (IRQ_SHPI_START + 124) +#define IRQ_DB8500_GPIO6 (IRQ_SHPI_START + 125) +#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) + +#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 diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h index 7970684b1d0..6f8f95dbd04 100644 --- a/arch/arm/mach-ux500/include/mach/irqs.h +++ b/arch/arm/mach-ux500/include/mach/irqs.h @@ -16,63 +16,47 @@ #define IRQ_LOCALWDOG 30 /* Shared Peripheral Interrupt (SHPI) */ -#define IRQ_SHPI_START 32 +#define IRQ_SPI_START 32 +#define IRQ_SHPI_START IRQ_SPI_START -/* Interrupt numbers generic for shared peripheral */ -#define IRQ_MTU0 (IRQ_SHPI_START + 4) -#define IRQ_SPI2 (IRQ_SHPI_START + 6) -#define IRQ_SPI0 (IRQ_SHPI_START + 8) -#define IRQ_UART0 (IRQ_SHPI_START + 11) -#define IRQ_I2C3 (IRQ_SHPI_START + 12) -#define IRQ_SSP0 (IRQ_SHPI_START + 14) -#define IRQ_MTU1 (IRQ_SHPI_START + 17) -#define IRQ_RTC_RTT (IRQ_SHPI_START + 18) -#define IRQ_UART1 (IRQ_SHPI_START + 19) -#define IRQ_I2C0 (IRQ_SHPI_START + 21) -#define IRQ_I2C1 (IRQ_SHPI_START + 22) -#define IRQ_USBOTG (IRQ_SHPI_START + 23) -#define IRQ_DMA (IRQ_SHPI_START + 25) -#define IRQ_UART2 (IRQ_SHPI_START + 26) -#define IRQ_HSIR_EXCEP (IRQ_SHPI_START + 29) -#define IRQ_MSP0 (IRQ_SHPI_START + 31) -#define IRQ_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32) -#define IRQ_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33) -#define IRQ_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34) -#define IRQ_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35) -#define IRQ_AB4500 (IRQ_SHPI_START + 40) -#define IRQ_DISP (IRQ_SHPI_START + 48) -#define IRQ_SiPI3 (IRQ_SHPI_START + 49) -#define IRQ_I2C4 (IRQ_SHPI_START + 51) -#define IRQ_SSP1 (IRQ_SHPI_START + 52) -#define IRQ_I2C2 (IRQ_SHPI_START + 55) -#define IRQ_SDMMC0 (IRQ_SHPI_START + 60) -#define IRQ_MSP1 (IRQ_SHPI_START + 62) -#define IRQ_SPI1 (IRQ_SHPI_START + 96) -#define IRQ_MSP2 (IRQ_SHPI_START + 98) -#define IRQ_SDMMC4 (IRQ_SHPI_START + 99) -#define IRQ_HSIRD0 (IRQ_SHPI_START + 104) -#define IRQ_HSIRD1 (IRQ_SHPI_START + 105) -#define IRQ_HSITD0 (IRQ_SHPI_START + 106) -#define IRQ_HSITD1 (IRQ_SHPI_START + 107) -#define IRQ_GPIO0 (IRQ_SHPI_START + 119) -#define IRQ_GPIO1 (IRQ_SHPI_START + 120) -#define IRQ_GPIO2 (IRQ_SHPI_START + 121) -#define IRQ_GPIO3 (IRQ_SHPI_START + 122) -#define IRQ_GPIO4 (IRQ_SHPI_START + 123) -#define IRQ_GPIO5 (IRQ_SHPI_START + 124) -#define IRQ_GPIO6 (IRQ_SHPI_START + 125) -#define IRQ_GPIO7 (IRQ_SHPI_START + 126) -#define IRQ_GPIO8 (IRQ_SHPI_START + 127) - -/* There are 128 shared peripheral interrupts assigned to - * INTID[160:32]. The first 32 interrupts are reserved. +/* + * 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 U8500_SOC_NR_IRQS 161 +#define IRQ_MTU0 (IRQ_SPI_START + 4) + +#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) + U8500_SOC_NR_IRQS) -#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - U8500_SOC_NR_IRQS) -#define NR_IRQS NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO) +#define U8500_NR_GPIO 268 +#define GPIO_TO_IRQ(gpio) (gpio + DBX500_NR_INTERNAL_IRQS) +#define IRQ_TO_GPIO(irq) (irq - DBX500_NR_INTERNAL_IRQS) + +#define NOMADIK_GPIO_TO_IRQ GPIO_TO_IRQ +#define NOMADIK_IRQ_TO_GPIO IRQ_TO_GPIO +#define IRQ_GPIO_END NOMADIK_GPIO_TO_IRQ(U8500_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 + +#if defined(CONFIG_MACH_U8500_MOP) \ + || defined(CONFIG_MACH_U8500_PDP) \ + || defined(CONFIG_MACH_U8500_SNOWBALL) +#include <mach/irqs-board-mop500.h> +#endif + +#if defined(CONFIG_MACH_B5500) +#include <mach/irqs-board-u5500.h> +#endif + +#define NR_IRQS IRQ_BOARD_END -#endif /*ASM_ARCH_IRQS_H*/ +#endif /* ASM_ARCH_IRQS_H */ diff --git a/arch/arm/mach-ux500/include/mach/isa_ioctl.h b/arch/arm/mach-ux500/include/mach/isa_ioctl.h new file mode 100644 index 00000000000..b05726f8c3c --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/isa_ioctl.h @@ -0,0 +1,51 @@ +/*---------------------------------------------------------------------------*/ +/* Copyright ST Ericsson, 2009. */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2.1 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/* See the GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/*---------------------------------------------------------------------------*/ +#ifndef __MODEM_IPC_INCLUDED +#define __MODEM_IPC_INCLUDED + +#define DLP_IOCTL_MAGIC_NUMBER 'M' +#define COMMON_BUFFER_SIZE (1024*1024) + +/** +DLP Message Structure for Userland +*/ +struct t_dlp_message{ + unsigned int offset; + unsigned int size; +}; + +/** +mmap constants. +*/ +enum t_dlp_mmap_params { + MMAP_DLQUEUE, + MMAP_ULQUEUE +}; + +/** +DLP IOCTLs for Userland +*/ +#define DLP_IOC_ALLOCATE_BUFFER \ + _IOWR(DLP_IOCTL_MAGIC_NUMBER, 0, struct t_dlp_message *) +#define DLP_IOC_DEALLOCATE_BUFFER \ + _IOWR(DLP_IOCTL_MAGIC_NUMBER, 1, struct t_dlp_message *) +#define DLP_IOC_GET_MESSAGE \ + _IOWR(DLP_IOCTL_MAGIC_NUMBER, 2, struct t_dlp_message *) +#define DLP_IOC_PUT_MESSAGE \ + _IOWR(DLP_IOCTL_MAGIC_NUMBER, 3, struct t_dlp_message *) + +#endif /*__MODEM_IPC_INCLUDED*/ + diff --git a/arch/arm/mach-ux500/include/mach/kpd.h b/arch/arm/mach-ux500/include/mach/kpd.h new file mode 100644 index 00000000000..ffff8eea193 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/kpd.h @@ -0,0 +1,123 @@ +/* + * Copyright STMicroelectronics, 2009. + * Copyright (C) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + */ + +#ifndef __U8500_KPD_H +#define __U8500_KPD_H + +#ifndef CONFIG_AUTOSCAN_ENABLED +#define CONFIG_AUTOSCAN_ENABLED 1 +#endif +#include <mach/hardware.h> +#include <linux/clk.h> + +#define MAX_KPROW 8 +#define MAX_KPCOL 8 +#define MAX_KEYS (MAX_KPROW * MAX_KPCOL) +/*keypad related Constants*/ +#define KEYPAD_RELEASE_PERIOD 11 /*11 msec, repeate key scan time */ +#define KEYPAD_SCAN_PERIOD 4 /*4msec for new keypress */ +#define KEYPAD_STATE_DEFAULT 0 +#define KEYPAD_STATE_PRESSED 1 +#define KEYPAD_STATE_PRESSACK 2 +#define KEYPAD_STATE_RELEASED 3 +#define KEYPAD_STATE_RELEASEACK 2 + +#define KPINTR_LKBIT 0 /*bit used for interrupt locking */ + +struct keypad_t; +/** + * struct keypad_device - Device data structure for platform specific data + * @init: pointer to keypad init function + * @exit: pointer to keypad deinitialisation function + * @autoscan_check: pointer to read autoscan status function + * currently + * @autoscan_disable: pointer to autoscan feature disable function, + * not used currently + * @autoscan_results: pointer to read autoscan results function + * @autoscan_en: pointer to enable autoscan feature function + * currently + * @irqen: pointer to enable irq function + * @irqdis: pointer to disable irq function + * @kcode_tbl: lookup table for keycodes + * @krow: mask for available rows, value is 0xFF + * @kcol: mask for available columns, value is 0xFF + * @irqdis_int: pointer to disable irq function, to be called from ISR + * @debounce_period: platform specific debounce time, can be fine tuned later + * @irqtype: type of interrupt + * @irq: irq no, + * @int_status: interrupt status + * @int_line_behaviour: dynamis interrupt line behaviour + * @enable_wakeup: specifies if keypad event can wake up system from sleep + */ +struct keypad_device { + int (*init)(struct keypad_t *kp); + int (*exit)(struct keypad_t *kp); + int (*autoscan_check)(void); + void (*autoscan_disable)(void); + int (*autoscan_results)(struct keypad_t *kp); + void (*autoscan_en)(void); + int (*irqen)(struct keypad_t *kp); + int (*irqdis)(struct keypad_t *kp); + u8 *kcode_tbl; + u8 krow; + u8 kcol; + int (*irqdis_int)(struct keypad_t *kp); + u8 debounce_period; + unsigned long irqtype; + u8 irq; + u8 int_status; + u8 int_line_behaviour; + bool enable_wakeup; +}; +/** + * struct keypad_t - keypad data structure used internally by keypad driver + * @irq: irq no + * @mode: 0 for interrupt mode, 1 for polling mode + * @ske_regs: ske regsiters base address + * @cr_lock: spinlock variable + * @key_state: array for saving keystates + * @lockbits: used for synchronisation in ISR + * @inp_dev: pointer to input device object + * @kscan_work: work queue + * @board: keypad platform device + * @key_cnt: count the keys pressed + * @clk: clock structure pointer + */ +struct keypad_t { + int irq; + int mode; + void __iomem *ske_regs; + int key_state[MAX_KPROW][MAX_KPCOL]; + unsigned long lockbits; + spinlock_t cr_lock; + struct input_dev *inp_dev; + struct delayed_work kscan_work; + struct keypad_device *board; + int key_cnt; + struct clk *clk; +}; +/** + * enum kp_int_status - enum for INTR status + * @KP_INT_DISABLED: interrupt disabled + * @KP_INT_ENABLED: interrupt enabled + */ +enum kp_int_status { + KP_INT_DISABLED = 0, + KP_INT_ENABLED, +}; +/** + *enum kp_int_line_behaviour - enum for kp_int_line dynamic status + * @INT_LINE_NOTSET: IRQ not asserted + * @INT_LINE_SET: IRQ asserted + */ +enum kp_int_line_behaviour { + INT_LINE_NOTSET = 0, + INT_LINE_SET, +}; +#endif /*__U8500_KPD_H*/ diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox.h new file mode 100644 index 00000000000..7f9da4d2fbd --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/mbox.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson. + * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __INC_STE_MBOX_H +#define __INC_STE_MBOX_H + +#define MBOX_BUF_SIZE 16 +#define MBOX_NAME_SIZE 8 + +/** + * mbox_recv_cb_t - Definition of the mailbox callback. + * @mbox_msg: The mailbox message. + * @priv: The clients private data as specified in the call to mbox_setup. + * + * This function will be called upon reception of new mailbox messages. + */ +typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv); + +/** + * struct mbox - Mailbox instance struct + * @list: Linked list head. + * @pdev: Pointer to device struct. + * @cb: Callback function. Will be called + * when new data is received. + * @client_data: Clients private data. Will be sent back + * in the callback function. + * @virtbase_peer: Virtual address for outgoing mailbox. + * @virtbase_local: Virtual address for incoming mailbox. + * @buffer: Then internal queue for outgoing messages. + * @name: Name of this mailbox. + * @buffer_available: Completion variable to achieve "blocking send". + * This variable will be signaled when there is + * internal buffer space available. + * @client_blocked: To keep track if any client is currently + * blocked. + * @lock: Spinlock to protect this mailbox instance. + * @write_index: Index in internal buffer to write to. + * @read_index: Index in internal buffer to read from. + * @allocated: Indicates whether this particular mailbox + * id has been allocated by someone. + */ +struct mbox { + struct list_head list; + struct platform_device *pdev; + mbox_recv_cb_t *cb; + void *client_data; + void __iomem *virtbase_peer; + void __iomem *virtbase_local; + u32 buffer[MBOX_BUF_SIZE]; + char name[MBOX_NAME_SIZE]; + struct completion buffer_available; + u8 client_blocked; + spinlock_t lock; + u8 write_index; + u8 read_index; + bool allocated; +}; + +/** + * mbox_setup - Set up a mailbox and return its instance. + * @mbox_id: The ID number of the mailbox. 0 or 1 for modem CPU, + * 2 for modem DSP. + * @mbox_cb: Pointer to the callback function to be called when a new message + * is received. + * @priv: Client user data which will be returned in the callback. + * + * Returns a mailbox instance to be specified in subsequent calls to mbox_send. + */ +struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv); + +/** + * mbox_send - Send a mailbox message. + * @mbox: Mailbox instance (returned by mbox_setup) + * @mbox_msg: The mailbox message to send. + * @block: Specifies whether this call will block until send is possible, + * or return an error if the mailbox buffer is full. + * + * Returns 0 on success or a negative error code on error. -ENOMEM indicates + * that the internal buffer is full and you have to try again later (or + * specify "block" in order to block until send is possible). + */ +int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block); + +#endif /*INC_STE_MBOX_H*/ diff --git a/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h b/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h new file mode 100644 index 00000000000..829b1708bf1 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com> for ST-Ericsson. + * Bibek Basu <bibek.basu@stericsson.com> + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __INC_MBOX_CHANNELS_H +#define __INC_MBOX_CHANNELS_H + +/* Maximum number of datawords which can be send in one PDU */ +#define MAILBOX_NR_OF_DATAWORDS 3 + +/** + * mbox_channel_cb_t - Definition of the mailbox channel callback. + * @data: Pointer to the data. + * @length: Length of the data. + * @priv: The client's private data. + * + * This function will be called upon reception of complete mbox channel PDU + * or after completion of send operation. + */ +typedef void mbox_channel_cb_t (u32 *data, u32 length, void *priv); + +/** + * mbox_channel_msg - Definition of mbox channel message + * @channel: Channel number. + * @data: Pointer to data to be sent. + * @length: Length of data to be sent. + * @cb: Pointer to the callback function to be called when send + * operation will be finished. + * @priv: The client's private data. + * + * This structure describes mailbox channel message. + */ +struct mbox_channel_msg { + u16 channel; + u32 *data; + u8 length; + mbox_channel_cb_t *cb; + void *priv; +}; + +/** mbox_channel_register - Set up a given mailbox channel. + * @channel: Mailbox channel number. + * @cb: Pointer to the callback function to be called when a new message + * is received. + * @priv: Client user data which will be returned in the callback. + * + * Returns 0 on success or a negative error code on error. + */ +int mbox_channel_register(u16 channel, mbox_channel_cb_t *cb, void *priv); + +/** + * mbox_channel_send - Send data on given mailbox channel. + * @msg: Mailbox channel message to be sent. + * + * Returns 0 on success or a negative error code on error. + */ +int mbox_channel_send(struct mbox_channel_msg *msg); + +/** + * mbox_channel_revoke_messages - Revoke messages on given mailbox channel. + * @channel: Mailbox channel number. + * + * Returns 0 on success or a negative error code on error. + */ +int mbox_channel_revoke_messages(u16 channel); + +#endif /*INC_STE_MBOX_H*/ + diff --git a/arch/arm/mach-ux500/include/mach/memory.h b/arch/arm/mach-ux500/include/mach/memory.h index 510571a59e2..e3def580cb9 100644 --- a/arch/arm/mach-ux500/include/mach/memory.h +++ b/arch/arm/mach-ux500/include/mach/memory.h @@ -15,4 +15,12 @@ #define PHYS_OFFSET UL(0x00000000) #define BUS_OFFSET UL(0x00000000) +#ifdef CONFIG_UX500_SOC_DB8500 +/* + * STE NMF CM driver only used on the U8500 allocate using dma_alloc_coherent: + * 8M for SIA and SVA data + 2M for SIA code + 2M for SVA code + */ +#define CONSISTENT_DMA_SIZE SZ_16M +#endif + #endif diff --git a/arch/arm/mach-ux500/include/mach/mloader-dbx500.h b/arch/arm/mach-ux500/include/mach/mloader-dbx500.h new file mode 100644 index 00000000000..68fa55a3f53 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/mloader-dbx500.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Ludovic Barre <ludovic.barre@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _MLOADER_UX500_H_ +#define _MLOADER_UX500_H_ + +/** + * struct dbx500_ml_area - data structure for modem memory areas description + * @name: name of the area + * @start: start address of the area + * @size: size of the area + */ +struct dbx500_ml_area { + const char *name; + u32 start; + u32 size; +}; + +/** + * struct dbx500_ml_fw - data stucture for modem firmwares description + * @name: firmware name + * @area: area where firmware is uploaded + * @offset: offset in the area where firmware is uploaded + */ +struct dbx500_ml_fw { + const char *name; + struct dbx500_ml_area *area; + u32 offset; +}; + +/** + * struct dbx500_mloader_pdata - data structure for platform specific data + * @fws: pointer on firmwares table + * @nr_fws: number of firmwares + * @areas: pointer on areas table + * @nr_areas: number of areas + */ +struct dbx500_mloader_pdata { + struct dbx500_ml_fw *fws; + int nr_fws; + struct dbx500_ml_area *areas; + int nr_areas; +}; + +#endif /* _MLOADER_UX500_H_ */ diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h new file mode 100644 index 00000000000..aecca3a59a3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/msp.h @@ -0,0 +1,970 @@ +/* + * Copyright (c) 2009 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#ifndef _STM_MSP_HEADER +#define _STM_MSP_HEADER +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/semaphore.h> +#include <linux/dmaengine.h> +#include <linux/i2s/i2s.h> +#include <linux/irqreturn.h> +#include <linux/bitops.h> +#include <plat/ste_dma40.h> +#include <mach/gpio.h> +#include <linux/spi/stm_msp.h> + +/* Generic config struct. Use the actual values defined below for global + * control register + */ + +enum msp_state { + MSP_STATE_IDLE = 0, + MSP_STATE_CONFIGURED = 1, + MSP_STATE_RUN = 2, +}; + +enum msp_rx_comparison_enable_mode { + MSP_COMPARISON_DISABLED = 0, + MSP_COMPARISON_NONEQUAL_ENABLED = 2, + MSP_COMPARISON_EQUAL_ENABLED = 3 +}; + +#define RMCEN_BIT 0 +#define RMCSF_BIT 1 +#define RCMPM_BIT 3 +#define TMCEN_BIT 5 +#define TNCSF_BIT 6 + +struct msp_multichannel_config { + bool rx_multichannel_enable; + bool tx_multichannel_enable; + enum msp_rx_comparison_enable_mode rx_comparison_enable_mode; + u8 padding; + u32 comparison_value; + u32 comparison_mask; + u32 rx_channel_0_enable; + u32 rx_channel_1_enable; + u32 rx_channel_2_enable; + u32 rx_channel_3_enable; + u32 tx_channel_0_enable; + u32 tx_channel_1_enable; + u32 tx_channel_2_enable; + u32 tx_channel_3_enable; +}; + +/** + * struct msp_protocol_desc- MSP Protocol desc structure per MSP. + * @rx_phase_mode: rx_phase_mode whether single or dual. + * @tx_phase_mode: tx_phase_mode whether single or dual. + * @rx_phase2_start_mode: rx_phase2_start_mode whether imediate or after + * some delay. + * @tx_phase2_start_mode: tx_phase2_start_mode whether imediate or after + * some delay. + * @rx_bit_transfer_format: MSP or LSB. + * @tx_bit_transfer_format: MSP or LSB. + * @rx_frame_length_1: Frame1 length 1,2,3.. + * @rx_frame_length_2: Frame2 length 1,2,3.. + * @tx_frame_length_1: Frame1 length 1,2,3.. + * @tx_frame_length_2: Frame2 length 1,2,3.. + * @rx_element_length_1: Element1 length 1,2,... + * @rx_element_length_2: Element2 length 1,2,... + * @tx_element_length_1: Element1 length 1,2,... + * @tx_element_length_2: Element2 length 1,2,... + * @rx_data_delay: Delay in clk cycle after frame sync + * @tx_data_delay: Delay in clk cycle after frame sync + * @rx_clock_pol: Rxpol whether rising or falling.It indicates pol of bit clock. + * @tx_clock_pol: Txpol whether rising or falling.It indicates pol of bit clock. + * @rx_frame_sync_pol: Frame sync pol whether rising or Falling. + * @tx_frame_sync_pol: Frame sync pol whether rising or Falling. + * @rx_half_word_swap: Word swap half word, full word. + * @tx_half_word_swap: Word swap half word, full word. + * @compression_mode: Compression mode whether Alaw or Ulaw or disabled. + * @expansion_mode: Compression mode whether Alaw or Ulaw or disabled. + * @spi_clk_mode: Spi clock mode to be enabled or not. + * @spi_burst_mode: Spi burst mode to be enabled or not. + * @frame_sync_ignore: Frame sync to be ignored or not. Ignore in case of Audio + * codec acting as Master. + * @frame_period: Frame period (clk cycles) after which new frame sync occurs. + * @frame_width: Frame width (clk cycles) after which frame sycn changes state. + * @total_clocks_for_one_frame: No. of clk cycles per frame. + * + * Main Msp protocol descriptor data structure to be used to store various info + * in transmit or recevie configuration registers of an MSP. + */ + +struct msp_protocol_desc { + u32 rx_phase_mode; + u32 tx_phase_mode; + u32 rx_phase2_start_mode; + u32 tx_phase2_start_mode; + u32 rx_bit_transfer_format; + u32 tx_bit_transfer_format; + u32 rx_frame_length_1; + u32 rx_frame_length_2; + u32 tx_frame_length_1; + u32 tx_frame_length_2; + u32 rx_element_length_1; + u32 rx_element_length_2; + u32 tx_element_length_1; + u32 tx_element_length_2; + u32 rx_data_delay; + u32 tx_data_delay; + u32 rx_clock_pol; + u32 tx_clock_pol; + u32 rx_frame_sync_pol; + u32 tx_frame_sync_pol; + u32 rx_half_word_swap; + u32 tx_half_word_swap; + u32 compression_mode; + u32 expansion_mode; + u32 spi_clk_mode; + u32 spi_burst_mode; + u32 frame_sync_ignore; + u32 frame_period; + u32 frame_width; + u32 total_clocks_for_one_frame; +}; + +/** + * struct trans_data - MSP transfer data structure used during xfer. + * @message: i2s message. + * @msp: msp structure. + * @tx_handler: callback handler for transmit path. + * @rx_handler: callback handler for receive path. + * @tx_callback_data: callback data for transmit. + * @rx_callback_data: callback data for receive. + * + */ +struct trans_data { + struct i2s_message message; + struct msp *msp; + void (*tx_handler) (void *data); + void (*rx_handler) (void *data); + void *tx_callback_data; + void *rx_callback_data; +}; + +/** + * struct msp_config- MSP configuration structure used by i2s client. + * @input_clock_freq: Input clock frequency default is 48MHz. + * @rx_clock_sel: Receive clock selection (Provided by Sample Gen or external + * source). + * @tx_clock_sel: Transmit clock selection (Provided by Sample Gen or external. + * source). + * @srg_clock_sel: APB clock or clock dervied from Slave (Audio codec). + * @rx_frame_sync_pol: Receive frame sync polarity. + * @tx_frame_sync_pol: Transmit frame sync polarity. + * @rx_frame_sync_sel: Rx frame sync signal is provided by which source. + * External source or by frame generator logic. + * @tx_frame_sync_sel: Tx frame sync signal is provided by which source. + * External source or by frame generator logic. + * @rx_fifo_config: Receive fifo enable or not. + * @tx_fifo_config: Transmit fifo enable or not. + * @spi_clk_mode: In case of SPI protocol spi modes: Normal, Zero delay or + * half cycle delay. + * @spi_burst_mode: Spi burst mode is enabled or not. + * @loopback_enable: Loopback mode. + * @tx_data_enable: Transmit extra delay enable. + * @default_protocol_desc: Flag to indicate client defined protocol desc or + * statically defined in msp.h. + * @protocol_desc: Protocol desc structure filled by i2s client driver. + * In case client defined default_prtocol_desc as 0. + * @multichannel_configured: multichannel configuration structure. + * @multichannel_config: multichannel is enabled or not. + * @direction: Transmit, Receive or Both. + * @work_mode: Dma, Polling or Interrupt. + * @protocol: I2S, PCM, etc. + * @frame_freq: Sampling freq at which data is sampled. + * @frame_size: size of element. + * @data_size: data size which defines the format in which data is written on + * transmit or receive fifo. Only three modes 8,16,32 are supported. + * @def_elem_len: Flag to indicate whether default element length is to be used + * or should be changed acc to data size defined by user at run time. + * @iodelay: value for the MSP_IODLY register + * @handler: callback handler in case of interrupt or dma. + * @tx_callback_data: Callback data for transmit. + * @rx_callback_data: Callback data for receive. + * + * Main Msp configuration data structure used by i2s client driver to fill + * various info like data size, frequency etc. + */ +struct msp_config { + unsigned int input_clock_freq; + unsigned int rx_clock_sel; + unsigned int tx_clock_sel; + unsigned int srg_clock_sel; + unsigned int rx_frame_sync_pol; + unsigned int tx_frame_sync_pol; + unsigned int rx_frame_sync_sel; + unsigned int tx_frame_sync_sel; + unsigned int rx_fifo_config; + unsigned int tx_fifo_config; + unsigned int spi_clk_mode; + unsigned int spi_burst_mode; + unsigned int loopback_enable; + unsigned int tx_data_enable; + unsigned int default_protocol_desc; + struct msp_protocol_desc protocol_desc; + int multichannel_configured; + struct msp_multichannel_config multichannel_config; + unsigned int direction; + unsigned int work_mode; + unsigned int protocol; + unsigned int frame_freq; + unsigned int frame_size; + enum msp_data_size data_size; + unsigned int def_elem_len; + unsigned int iodelay; + void (*handler) (void *data); + void *tx_callback_data; + void *rx_callback_data; + +}; + +/*** Protocols ***/ +enum msp_protocol { + MSP_I2S_PROTOCOL, + MSP_PCM_PROTOCOL, + MSP_PCM_COMPAND_PROTOCOL, + MSP_AC97_PROTOCOL, + MSP_MASTER_SPI_PROTOCOL, + MSP_SLAVE_SPI_PROTOCOL, + MSP_INVALID_PROTOCOL +}; + +/*** Sample Frequencies ***/ +/* These are no longer required, frequencies in Hz can be used directly */ +enum msp_sample_freq { + MSP_SAMPLE_FREQ_NOT_SUPPORTED = -1, + MSP_SAMPLE_FREQ_8KHZ = 8000, + MSP_SAMPLE_FREQ_12KHZ = 12000, + MSP_SAMPLE_FREQ_16KHZ = 16000, + MSP_SAMPLE_FREQ_24KHZ = 24000, + MSP_SAMPLE_FREQ_32KHZ = 32000, + MSP_SAMPLE_FREQ_44KHZ = 44000, + MSP_SAMPLE_FREQ_48KHZ = 48000, + MSP_SAMPLE_FREQ_64KHZ = 64000, + MSP_SAMPLE_FREQ_88KHZ = 88000, + MSP_SAMPLE_FREQ_96KHZ = 96000, + MSP_SAMPLE_FREQ_22KHZ = 22000, + MSP_SAMPLE_FREQ_11KHZ = 11000 +}; + +/*** Input Frequencies ***/ +/* These are no longer required, frequencies in Hz can be used directly */ +enum msp_in_clock_freq { + MSP_INPUT_FREQ_1MHZ = 1000, + MSP_INPUT_FREQ_2MHZ = 2000, + MSP_INPUT_FREQ_3MHZ = 3000, + MSP_INPUT_FREQ_4MHZ = 4000, + MSP_INPUT_FREQ_5MHZ = 5000, + MSP_INPUT_FREQ_6MHZ = 6000, + MSP_INPUT_FREQ_8MHZ = 8000, + MSP_INPUT_FREQ_11MHZ = 11000, + MSP_INPUT_FREQ_12MHZ = 12000, + MSP_INPUT_FREQ_16MHZ = 16000, + MSP_INPUT_FREQ_22MHZ = 22000, + MSP_INPUT_FREQ_24MHZ = 24000, + MSP_INPUT_FREQ_48MHZ = 48000 +}; + +#define MSP_INPUT_FREQ_APB 48000000 + +/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono), + * 32 bits accesses (stereo). + ***/ +enum msp_stereo_mode { + MSP_MONO, + MSP_STEREO +}; + +/* Direction (Transmit/Receive mode) */ +enum msp_direction { + MSP_TRANSMIT_MODE, + MSP_RECEIVE_MODE, + MSP_BOTH_T_R_MODE +}; + +/* Dma mode should be used for large transfers, + * polling mode should be used for transfers of a few bytes + */ +enum msp_xfer_mode { + MSP_DMA_MODE, + MSP_POLLING_MODE, + MSP_INTERRUPT_MODE +}; + +/* User client for the MSP */ +enum msp_user { + MSP_NO_USER = 0, + MSP_USER_SPI, + MSP_USER_ALSA, + MSP_USER_SAA, +}; + +/*Flag structure for MSPx*/ +struct msp_flag { + struct semaphore lock; + enum msp_user user; +}; + +/* User client for the MSP */ +enum msp_mode { + MSP_NO_MODE = 0, + MSP_MODE_SPI, + MSP_MODE_NON_SPI, +}; + +/* Transmit and receive configuration register */ +#define MSP_BIG_ENDIAN 0x00000000 +#define MSP_LITTLE_ENDIAN 0x00001000 +#define MSP_UNEXPECTED_FS_ABORT 0x00000000 +#define MSP_UNEXPECTED_FS_IGNORE 0x00008000 +#define MSP_NON_MODE_BIT_MASK 0x00009000 + +/* Global configuration register */ +#define RX_ENABLE 0x00000001 +#define RX_FIFO_ENABLE 0x00000002 +#define RX_SYNC_SRG 0x00000010 +#define RX_CLK_POL_RISING 0x00000020 +#define RX_CLK_SEL_SRG 0x00000040 +#define TX_ENABLE 0x00000100 +#define TX_FIFO_ENABLE 0x00000200 +#define TX_SYNC_SRG_PROG 0x00001800 +#define TX_SYNC_SRG_AUTO 0x00001000 +#define TX_CLK_POL_RISING 0x00002000 +#define TX_CLK_SEL_SRG 0x00004000 +#define TX_EXTRA_DELAY_ENABLE 0x00008000 +#define SRG_ENABLE 0x00010000 +#define FRAME_GEN_ENABLE 0x00100000 +#define SRG_CLK_SEL_APB 0x00000000 +#define RX_FIFO_SYNC_HI 0x00000000 +#define TX_FIFO_SYNC_HI 0x00000000 +#define SPI_CLK_MODE_NORMAL 0x00000000 + +/* SPI Clock Modes enumertion + * SPI clock modes of MSP provides compatibility with + * the SPI protocol.MSP supports 2 SPI transfer formats. + * MSP_ZERO_DELAY_SPI_MODE:MSP transmits data over Tx/Rx + * Lines immediately after MSPTCK/MSPRCK rising/falling edge. + * MSP_HALF_CYCLE_DELY_SPI_MODE:MSP transmits data one-half cycle + * ahead of the rising/falling edge of the MSPTCK + */ + +#define MSP_FRAME_SIZE_AUTO -1 + + +#define MSP_DR 0x00 +#define MSP_GCR 0x04 +#define MSP_TCF 0x08 +#define MSP_RCF 0x0c +#define MSP_SRG 0x10 +#define MSP_FLR 0x14 +#define MSP_DMACR 0x18 + +#define MSP_IMSC 0x20 +#define MSP_RIS 0x24 +#define MSP_MIS 0x28 +#define MSP_ICR 0x2c +#define MSP_MCR 0x30 +#define MSP_RCV 0x34 +#define MSP_RCM 0x38 + +#define MSP_TCE0 0x40 +#define MSP_TCE1 0x44 +#define MSP_TCE2 0x48 +#define MSP_TCE3 0x4c + +#define MSP_RCE0 0x60 +#define MSP_RCE1 0x64 +#define MSP_RCE2 0x68 +#define MSP_RCE3 0x6c +#define MSP_IODLY 0x70 + +#define MSP_ITCR 0x80 +#define MSP_ITIP 0x84 +#define MSP_ITOP 0x88 +#define MSP_TSTDR 0x8c + +#define MSP_PID0 0xfe0 +#define MSP_PID1 0xfe4 +#define MSP_PID2 0xfe8 +#define MSP_PID3 0xfec + +#define MSP_CID0 0xff0 +#define MSP_CID1 0xff4 +#define MSP_CID2 0xff8 +#define MSP_CID3 0xffc + +/* Single or dual phase mode */ +enum msp_phase_mode { + MSP_SINGLE_PHASE, + MSP_DUAL_PHASE +}; + +/* Frame length */ +enum msp_frame_length { + MSP_FRAME_LENGTH_1 = 0, + MSP_FRAME_LENGTH_2 = 1, + MSP_FRAME_LENGTH_4 = 3, + MSP_FRAME_LENGTH_8 = 7, + MSP_FRAME_LENGTH_12 = 11, + MSP_FRAME_LENGTH_16 = 15, + MSP_FRAME_LENGTH_20 = 19, + MSP_FRAME_LENGTH_32 = 31, + MSP_FRAME_LENGTH_48 = 47, + MSP_FRAME_LENGTH_64 = 63 +}; + +/* Element length */ +enum msp_elem_length { + MSP_ELEM_LENGTH_8 = 0, + MSP_ELEM_LENGTH_10 = 1, + MSP_ELEM_LENGTH_12 = 2, + MSP_ELEM_LENGTH_14 = 3, + MSP_ELEM_LENGTH_16 = 4, + MSP_ELEM_LENGTH_20 = 5, + MSP_ELEM_LENGTH_24 = 6, + MSP_ELEM_LENGTH_32 = 7 +}; + +enum msp_data_xfer_width { + MSP_DATA_TRANSFER_WIDTH_BYTE, + MSP_DATA_TRANSFER_WIDTH_HALFWORD, + MSP_DATA_TRANSFER_WIDTH_WORD +}; + +enum msp_frame_sync { + MSP_FRAME_SYNC_UNIGNORE = 0, + MSP_FRAME_SYNC_IGNORE = 1, + +}; + +enum msp_phase2_start_mode { + MSP_PHASE2_START_MODE_IMEDIATE, + MSP_PHASE2_START_MODE_FRAME_SYNC +}; + +enum msp_btf { + MSP_BTF_MS_BIT_FIRST = 0, + MSP_BTF_LS_BIT_FIRST = 1 +}; + +enum msp_frame_sync_pol { + MSP_FRAME_SYNC_POL_ACTIVE_HIGH = 0, + MSP_FRAME_SYNC_POL_ACTIVE_LOW = 1 +}; + +/* Data delay (in bit clock cycles) */ +enum msp_delay { + MSP_DELAY_0 = 0, + MSP_DELAY_1 = 1, + MSP_DELAY_2 = 2, + MSP_DELAY_3 = 3 +}; + +/* Configurations of clocks (transmit, receive or sample rate generator) */ +enum msp_edge { + MSP_FALLING_EDGE = 0, + MSP_RISING_EDGE = 1, +}; + +enum msp_hws { + MSP_HWS_NO_SWAP = 0, + MSP_HWS_BYTE_SWAP_IN_WORD = 1, + MSP_HWS_BYTE_SWAP_IN_EACH_HALF_WORD = 2, + MSP_HWS_HALF_WORD_SWAP_IN_WORD = 3 +}; + +enum msp_compress_mode { + MSP_COMPRESS_MODE_LINEAR = 0, + MSP_COMPRESS_MODE_MU_LAW = 2, + MSP_COMPRESS_MODE_A_LAW = 3 +}; + +enum msp_spi_clock_mode { + MSP_SPI_CLOCK_MODE_NON_SPI = 0, + MSP_SPI_CLOCK_MODE_ZERO_DELAY = 2, + MSP_SPI_CLOCK_MODE_HALF_CYCLE_DELAY = 3 +}; + +enum msp_spi_burst_mode { + MSP_SPI_BURST_MODE_DISABLE = 0, + MSP_SPI_BURST_MODE_ENABLE = 1 +}; + +enum msp_expand_mode { + MSP_EXPAND_MODE_LINEAR = 0, + MSP_EXPAND_MODE_LINEAR_SIGNED = 1, + MSP_EXPAND_MODE_MU_LAW = 2, + MSP_EXPAND_MODE_A_LAW = 3 +}; + +/* Protocol dependant parameters list */ +#define RX_ENABLE_MASK BIT(0) +#define RX_FIFO_ENABLE_MASK BIT(1) +#define RX_FRAME_SYNC_MASK BIT(2) +#define DIRECT_COMPANDING_MASK BIT(3) +#define RX_SYNC_SEL_MASK BIT(4) +#define RX_CLK_POL_MASK BIT(5) +#define RX_CLK_SEL_MASK BIT(6) +#define LOOPBACK_MASK BIT(7) +#define TX_ENABLE_MASK BIT(8) +#define TX_FIFO_ENABLE_MASK BIT(9) +#define TX_FRAME_SYNC_MASK BIT(10) +#define TX_MSP_TDR_TSR BIT(11) +#define TX_SYNC_SEL_MASK (BIT(12) | BIT(11)) +#define TX_CLK_POL_MASK BIT(13) +#define TX_CLK_SEL_MASK BIT(14) +#define TX_EXTRA_DELAY_MASK BIT(15) +#define SRG_ENABLE_MASK BIT(16) +#define SRG_CLK_POL_MASK BIT(17) +#define SRG_CLK_SEL_MASK (BIT(19) | BIT(18)) +#define FRAME_GEN_EN_MASK BIT(20) +#define SPI_CLK_MODE_MASK (BIT(22) | BIT(21)) +#define SPI_BURST_MODE_MASK BIT(23) + +#define RXEN_SHIFT 0 +#define RFFEN_SHIFT 1 +#define RFSPOL_SHIFT 2 +#define DCM_SHIFT 3 +#define RFSSEL_SHIFT 4 +#define RCKPOL_SHIFT 5 +#define RCKSEL_SHIFT 6 +#define LBM_SHIFT 7 +#define TXEN_SHIFT 8 +#define TFFEN_SHIFT 9 +#define TFSPOL_SHIFT 10 +#define TFSSEL_SHIFT 11 +#define TCKPOL_SHIFT 13 +#define TCKSEL_SHIFT 14 +#define TXDDL_SHIFT 15 +#define SGEN_SHIFT 16 +#define SCKPOL_SHIFT 17 +#define SCKSEL_SHIFT 18 +#define FGEN_SHIFT 20 +#define SPICKM_SHIFT 21 +#define TBSWAP_SHIFT 28 + +#define RCKPOL_MASK BIT(0) +#define TCKPOL_MASK BIT(0) +#define SPICKM_MASK (BIT(1) | BIT(0)) +#define MSP_RX_CLKPOL_BIT(n) ((n & RCKPOL_MASK) << RCKPOL_SHIFT) +#define MSP_TX_CLKPOL_BIT(n) ((n & TCKPOL_MASK) << TCKPOL_SHIFT) +#define MSP_SPI_CLK_MODE_BITS(n) ((n & SPICKM_MASK) << SPICKM_SHIFT) + + + +/* Use this to clear the clock mode bits to non-spi */ +#define MSP_NON_SPI_CLK_MASK (BIT(22) | BIT(21)) + +#define P1ELEN_SHIFT 0 +#define P1FLEN_SHIFT 3 +#define DTYP_SHIFT 10 +#define ENDN_SHIFT 12 +#define DDLY_SHIFT 13 +#define FSIG_SHIFT 15 +#define P2ELEN_SHIFT 16 +#define P2FLEN_SHIFT 19 +#define P2SM_SHIFT 26 +#define P2EN_SHIFT 27 +#define FRAME_SYNC_SHIFT 15 + + +#define P1ELEN_MASK 0x00000007 +#define P2ELEN_MASK 0x00070000 +#define P1FLEN_MASK 0x00000378 +#define P2FLEN_MASK 0x03780000 +#define DDLY_MASK 0x00003000 +#define DTYP_MASK 0x00000600 +#define P2SM_MASK 0x04000000 +#define P2EN_MASK 0x08000000 +#define ENDN_MASK 0x00001000 +#define TFSPOL_MASK 0x00000400 +#define TBSWAP_MASK 0x30000000 +#define COMPANDING_MODE_MASK 0x00000c00 +#define FRAME_SYNC_MASK 0x00008000 + +#define MSP_P1_ELEM_LEN_BITS(n) (n & P1ELEN_MASK) +#define MSP_P2_ELEM_LEN_BITS(n) (((n) << P2ELEN_SHIFT) & P2ELEN_MASK) +#define MSP_P1_FRAME_LEN_BITS(n) (((n) << P1FLEN_SHIFT) & P1FLEN_MASK) +#define MSP_P2_FRAME_LEN_BITS(n) (((n) << P2FLEN_SHIFT) & P2FLEN_MASK) +#define MSP_DATA_DELAY_BITS(n) (((n) << DDLY_SHIFT) & DDLY_MASK) +#define MSP_DATA_TYPE_BITS(n) (((n) << DTYP_SHIFT) & DTYP_MASK) +#define MSP_P2_START_MODE_BIT(n) ((n << P2SM_SHIFT) & P2SM_MASK) +#define MSP_P2_ENABLE_BIT(n) ((n << P2EN_SHIFT) & P2EN_MASK) +#define MSP_SET_ENDIANNES_BIT(n) ((n << ENDN_SHIFT) & ENDN_MASK) +#define MSP_FRAME_SYNC_POL(n) ((n << TFSPOL_SHIFT) & TFSPOL_MASK) +#define MSP_DATA_WORD_SWAP(n) ((n << TBSWAP_SHIFT) & TBSWAP_MASK) +#define MSP_SET_COMPANDING_MODE(n) ((n << DTYP_SHIFT) & COMPANDING_MODE_MASK) +#define MSP_SET_FRAME_SYNC_IGNORE(n) ((n << FRAME_SYNC_SHIFT) & \ + FRAME_SYNC_MASK) + +/* Flag register */ +#define RX_BUSY BIT(0) +#define RX_FIFO_EMPTY BIT(1) +#define RX_FIFO_FULL BIT(2) +#define TX_BUSY BIT(3) +#define TX_FIFO_EMPTY BIT(4) +#define TX_FIFO_FULL BIT(5) + +#define RBUSY_SHIFT 0 +#define RFE_SHIFT 1 +#define RFU_SHIFT 2 +#define TBUSY_SHIFT 3 +#define TFE_SHIFT 4 +#define TFU_SHIFT 5 + +/* Multichannel control register */ +#define RMCEN_SHIFT 0 +#define RMCSF_SHIFT 1 +#define RCMPM_SHIFT 3 +#define TMCEN_SHIFT 5 +#define TNCSF_SHIFT 6 + +/* Sample rate generator register */ +#define SCKDIV_SHIFT 0 +#define FRWID_SHIFT 10 +#define FRPER_SHIFT 16 + +#define SCK_DIV_MASK 0x0000003FF +#define FRAME_WIDTH_BITS(n) (((n) << FRWID_SHIFT) & 0x0000FC00) +#define FRAME_PERIOD_BITS(n) (((n) << FRPER_SHIFT) & 0x1FFF0000) + +/* DMA controller register */ +#define RX_DMA_ENABLE BIT(0) +#define TX_DMA_ENABLE BIT(1) + +#define RDMAE_SHIFT 0 +#define TDMAE_SHIFT 1 + +/* Interrupt Register */ +#define RECEIVE_SERVICE_INT BIT(0) +#define RECEIVE_OVERRUN_ERROR_INT BIT(1) +#define RECEIVE_FRAME_SYNC_ERR_INT BIT(2) +#define RECEIVE_FRAME_SYNC_INT BIT(3) +#define TRANSMIT_SERVICE_INT BIT(4) +#define TRANSMIT_UNDERRUN_ERR_INT BIT(5) +#define TRANSMIT_FRAME_SYNC_ERR_INT BIT(6) +#define TRANSMIT_FRAME_SYNC_INT BIT(7) +#define ALL_INT 0x000000ff + +/* + * Protocol configuration values I2S: + * Single phase, 16 bits, 2 words per frame + */ +#define I2S_PROTOCOL_DESC \ +{ \ + MSP_SINGLE_PHASE, \ + MSP_SINGLE_PHASE, \ + MSP_PHASE2_START_MODE_IMEDIATE, \ + MSP_PHASE2_START_MODE_IMEDIATE, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_ELEM_LENGTH_32, \ + MSP_ELEM_LENGTH_32, \ + MSP_ELEM_LENGTH_32, \ + MSP_ELEM_LENGTH_32, \ + MSP_DELAY_1, \ + MSP_DELAY_1, \ + MSP_RISING_EDGE, \ + MSP_RISING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 31, \ + 15, \ + 32, \ +} + +#define PCM_PROTOCOL_DESC \ +{ \ + MSP_DUAL_PHASE, \ + MSP_DUAL_PHASE, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_ELEM_LENGTH_16, \ + MSP_ELEM_LENGTH_16, \ + MSP_ELEM_LENGTH_16, \ + MSP_ELEM_LENGTH_16, \ + MSP_DELAY_0, \ + MSP_DELAY_0, \ + MSP_FALLING_EDGE, \ + MSP_FALLING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 255, \ + 0, \ + 256, \ +} + +/* Companded PCM: Single phase, 8 bits, 1 word per frame */ +#define PCM_COMPAND_PROTOCOL_DESC \ +{ \ + MSP_SINGLE_PHASE, \ + MSP_SINGLE_PHASE, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_DELAY_0, \ + MSP_DELAY_0, \ + MSP_FALLING_EDGE, \ + MSP_RISING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 255, \ + 0, \ + 256, \ +} + +/* + * AC97: Double phase, 1 element of 16 bits during first phase, + * 12 elements of 20 bits in second phase. + */ +#define AC97_PROTOCOL_DESC \ +{ \ + MSP_DUAL_PHASE, \ + MSP_DUAL_PHASE, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_12, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_12, \ + MSP_ELEM_LENGTH_16, \ + MSP_ELEM_LENGTH_20, \ + MSP_ELEM_LENGTH_16, \ + MSP_ELEM_LENGTH_20, \ + MSP_DELAY_1, \ + MSP_DELAY_1, \ + MSP_FALLING_EDGE, \ + MSP_RISING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 255, \ + 0, \ + 256, \ +} + +#define SPI_MASTER_PROTOCOL_DESC \ +{ \ + MSP_SINGLE_PHASE, \ + MSP_SINGLE_PHASE, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_DELAY_1, \ + MSP_DELAY_1, \ + MSP_RISING_EDGE, \ + MSP_FALLING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 255, \ + 0, \ + 256, \ +} + +#define SPI_SLAVE_PROTOCOL_DESC \ +{ \ + MSP_SINGLE_PHASE, \ + MSP_SINGLE_PHASE, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_PHASE2_START_MODE_FRAME_SYNC, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_BTF_MS_BIT_FIRST, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_FRAME_LENGTH_1, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_ELEM_LENGTH_8, \ + MSP_DELAY_1, \ + MSP_DELAY_1, \ + MSP_RISING_EDGE, \ + MSP_FALLING_EDGE, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \ + MSP_HWS_NO_SWAP, \ + MSP_HWS_NO_SWAP, \ + MSP_COMPRESS_MODE_LINEAR, \ + MSP_EXPAND_MODE_LINEAR, \ + MSP_SPI_CLOCK_MODE_NON_SPI, \ + MSP_SPI_BURST_MODE_DISABLE, \ + MSP_FRAME_SYNC_IGNORE, \ + 255, \ + 0, \ + 256, \ +} + +#define MSP_FRAME_PERIOD_IN_MONO_MODE 256 +#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32 +#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16 + +/* + * No of registers to backup during + * suspend resume + */ +#define MAX_MSP_BACKUP_REGS 36 + +enum enum_i2s_controller { + MSP_0_I2S_CONTROLLER = 1, + MSP_1_I2S_CONTROLLER, + MSP_2_I2S_CONTROLLER, + MSP_3_I2S_CONTROLLER, +}; + +/** + * struct msp - Main msp controller data structure per MSP. + * @work_mode: Mode i.e dma, polling or interrupt. + * @id: Controller id like MSP1 or MSP2 etc. + * @msp_io_error: To indicate error while transferring. + * @registers: MSP's register base address. + * @actual_data_size: Data size in which data needs to send or receive. + * @irq: MSP's irq number. + * @i2s_cont: MSP's Controller's structure pointer created per MSP. + * @lock: semaphore lock acquired while configuring msp. + * @dma_cfg_tx: TX DMA configuration + * @dma_cfg_rx: RX DMA configuration + * @tx_pipeid: TX DMA channel + * @rx_pipeid: RX DMA channel + * @msp_state: Current state of msp. + * @read: Function pointer for read, u8_msp_read,u16_msp_read,u32_msp_read. + * @write: Function pointer for write, u8_msp_write,u16_msp_write,u32_msp_write. + * @transfer: Function pointer for type of transfer i.e dma,polling or interrupt + * @xfer_data: MSP's transfer data structure. Contains info about current xfer. + * @plat_init: MSP's initialization function. + * @plat_exit: MSP's Exit function. + * @notify_timer: Timer used in Polling mode to prevent hang. + * @polling_flag: Flag used in error handling while polling. + * @def_elem_len: Flag indicates whether default elem len to be used in + * protocol_desc or not. + * @vape_opp_constraint: 1 if constraint is applied to have vape at 100OPP; 0 otherwise + * @infinite: true if an infinite transfer has been configured + * + * Main Msp private data structure to be used to store various info of a + * particular MSP.Longer description + */ +struct msp { + int work_mode; + enum enum_i2s_controller id; + int msp_io_error; + void __iomem *registers; + enum msp_data_size actual_data_size; + int irq; + struct i2s_controller *i2s_cont; + struct semaphore lock; + struct stedma40_chan_cfg *dma_cfg_rx; + struct stedma40_chan_cfg *dma_cfg_tx; + struct dma_chan *tx_pipeid; + struct dma_chan *rx_pipeid; + enum msp_state msp_state; + void (*read) (struct trans_data *xfer_data); + void (*write) (struct trans_data *xfer_data); + int (*transfer) (struct msp *msp, struct i2s_message *message); + struct trans_data xfer_data; + int (*plat_init) (void); + int (*plat_exit) (void); + struct timer_list notify_timer; + int polling_flag; + int def_elem_len; + struct clk *clk; + unsigned int direction; + int users; + int loopback_enable; + u32 backup_regs[MAX_MSP_BACKUP_REGS]; + int vape_opp_constraint; + bool infinite; +}; + +/** + * struct msp_i2s_platform_data - Main msp controller platform data structure. + * @id: Controller id like MSP1 or MSP2 etc. + * @msp_i2s_dma_rx: RX DMA channel config + * @msp_i2s_dma_tx: RX DMA channel config + * @msp_i2s_init: MSP's initialization function. + * @msp_i2s_exit: MSP's Exit function. + * @backup_regs: used for backup registers during suspend resume. + * + * Platform data structure passed by devices.c file. + */ +struct msp_i2s_platform_data { + enum enum_i2s_controller id; + struct stedma40_chan_cfg *msp_i2s_dma_rx; + struct stedma40_chan_cfg *msp_i2s_dma_tx; + int (*msp_i2s_init) (void); + int (*msp_i2s_exit) (void); +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/musb_db8500.h b/arch/arm/mach-ux500/include/mach/musb_db8500.h new file mode 100644 index 00000000000..7e210ca3dc9 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/musb_db8500.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 ST Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* AB8500 USB macros + */ +#define AB8500_REV_10 0x10 +#define AB8500_REV_11 0x11 +#define AB8500_REV_20 0x20 +#define AB8500_REV_30 0x30 +#define AB8500_USB_HOST 0x68 +#define AB8500_USB_LINK_STATUS_UPDT_DONE 135 +#define AB8500_IT_MASK20_MASK 0xFB +#define AB8500_IT_MASK21_MASK 0xBE +#define AB8500_IT_MASK2_MASK 0x3F +#define AB8500_IT_MASK12_MASK 0x7F +#define AB8500_SRC_INT_USB_DEVICE 0x80 +#define AB8500_SRC_INT_USB_HOST 0x04 +#define AB8500_VBUS_ENABLE 0x1 +#define AB8500_VBUS_DISABLE 0x0 +#define AB8500_USB_HOST_DEVICE_DISABLE 0x0 +#define AB8500_USB_HOST_ENABLE 0x1 +#define AB8500_USB_HOST_DISABLE 0x0 +#define AB8500_USB_DEVICE_ENABLE 0x2 +#define AB8500_USB_DEVICE_DISABLE 0x0 +#define AB8500_MAIN_WATCHDOG_ENABLE 0x1 +#define AB8500_MAIN_WATCHDOG_KICK 0x2 +#define AB8500_MAIN_WATCHDOG_DISABLE 0x0 +#define AB8500_USB_ADP_ENABLE 0x1 + +/* USB Macros + */ +#define WATCHDOG_DELAY 10 +#define WATCHDOG_DELAY_US 100 +#define USB_ENABLE 1 +#define USB_DISABLE 0 + +/* UsbLineStatus register bit masks */ +#define AB8500_USB_LINK_STATUS 0x78 + +/* UsbLineStatus register - usb types */ +enum musb_link_status { + USB_LINK_NOT_CONFIGURED, + USB_LINK_STD_HOST_NC, + USB_LINK_STD_HOST_C_NS, + USB_LINK_STD_HOST_C_S, + USB_LINK_HOST_CHG_NM, + USB_LINK_HOST_CHG_HS, + USB_LINK_HOST_CHG_HS_CHIRP, + USB_LINK_DEDICATED_CHG, + USB_LINK_ACA_RID_A, + USB_LINK_ACA_RID_B, + USB_LINK_ACA_RID_C_NM, + USB_LINK_ACA_RID_C_HS, + USB_LINK_ACA_RID_C_HS_CHIRP, + USB_LINK_HM_IDGND, + USB_LINK_OTG_HOST_NO_CURRENT, + USB_LINK_NOT_VALID_LINK, +}; + +/* Specific functions for USB Phy enable and disable + */ +int musb_phy_en(u8 mode); +int musb_force_detect(u8 mode); +int musb_get_abx500_rev(void); + diff --git a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h new file mode 100644 index 00000000000..d55ee1a51f3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h @@ -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_U5500_PRCMU + +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_U5500_PRCMU */ + +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_U5500_PRCMU */ + +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 */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h b/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h new file mode 100644 index 00000000000..56402a115ed --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h @@ -0,0 +1,532 @@ +/* + * 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 __MACH_PRCMU_FW_API_H +#define __MACH_PRCMU_FW_API_H + +#include <linux/interrupt.h> +#include <linux/notifier.h> +#include "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_PLLSOC1, + PRCMU_TIMCLK, +}; + +/* + * Definitions for controlling ESRAM0 in deep sleep. + */ +#define ESRAM0_DEEP_SLEEP_STATE_OFF 1 +#define ESRAM0_DEEP_SLEEP_STATE_RET 2 + +#if defined(CONFIG_U8500_PRCMU) || defined(CONFIG_U5500_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_U8500_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); +void prcmu_qos_force_opp(int, s32); +/* 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_U8500_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 void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) {} + +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; +} + +static inline 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; +} + +static inline int prcmu_set_epod(u16 epod_id, u8 epod_state) +{ + return 0; +} + +#ifndef CONFIG_U5500_PRCMU +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_U8500_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 /* __MACH_PRCMU_FW_API_V1_H */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h b/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h new file mode 100644 index 00000000000..42a8cd2310f --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h @@ -0,0 +1,467 @@ +/* + * 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 definitions for U8500 v1.0 cut + */ +#ifndef __MACH_PRCMU_FW_DEFS_V1_H +#define __MACH_PRCMU_FW_DEFS_V1_H + +#include <linux/interrupt.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, +}; + +#endif /* __MACH_PRCMU_FW_DEFS_V1_H */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h new file mode 100644 index 00000000000..5478a553d60 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ +#ifndef __MACH_PRCMU_REGS_H +#define __MACH_PRCMU_REGS_H + +#include <mach/hardware.h> + +#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) +#define PRCM_ARM_LS_CLAMP (_PRCMU_BASE + 0x30c) +#define PRCM_SRAM_A9 (_PRCMU_BASE + 0x308) + +/* ARM WFI Standby signal register */ +#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130) +#define PRCM_IOCR (_PRCMU_BASE + 0x310) +#define PRCM_IOCR_IOFORCE 0x1 + +/* CPU mailbox registers */ +#define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc) +#define PRCM_MBOX_CPU_SET (_PRCMU_BASE + 0x100) +#define PRCM_MBOX_CPU_CLR (_PRCMU_BASE + 0x104) + +/* 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) +#define PRCM_ARMITMSK95TO64 (_PRCMU_BASE + 0x124) +#define PRCM_ARMITMSK127TO96 (_PRCMU_BASE + 0x128) +#define PRCM_POWER_STATE_VAL (_PRCMU_BASE + 0x25C) +#define PRCM_ARMITVAL31TO0 (_PRCMU_BASE + 0x260) +#define PRCM_ARMITVAL63TO32 (_PRCMU_BASE + 0x264) +#define PRCM_ARMITVAL95TO64 (_PRCMU_BASE + 0x268) +#define PRCM_ARMITVAL127TO96 (_PRCMU_BASE + 0x26C) + +#define PRCM_HOSTACCESS_REQ (_PRCMU_BASE + 0x334) +#define ARM_WAKEUP_MODEM 0x1 + +#define PRCM_ARM_IT1_CLEAR (_PRCMU_BASE + 0x48C) +#define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494) +#define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174) + +#define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148) +#define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150) +#define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158) +#define PRCM_ITSTATUS3 (_PRCMU_BASE + 0x160) +#define PRCM_ITSTATUS4 (_PRCMU_BASE + 0x168) +#define PRCM_ITSTATUS5 (_PRCMU_BASE + 0x484) +#define PRCM_ITCLEAR5 (_PRCMU_BASE + 0x488) +#define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018) + +/* System reset register */ +#define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228) + +/* Level shifter and clamp control registers */ +#define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420) +#define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424) + +/* 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) +#define PRCM_SRAM_LS_SLEEP (_PRCMU_BASE + 0x304) + +/* Debug power control unit registers */ +#define PRCM_POWER_STATE_SET (_PRCMU_BASE + 0x254) + +/* 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 */ diff --git a/arch/arm/mach-ux500/include/mach/reboot_reasons.h b/arch/arm/mach-ux500/include/mach/reboot_reasons.h new file mode 100644 index 00000000000..06a73754b56 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/reboot_reasons.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Rickard Evertsson <rickard.evertsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL) version 2 + * + * Use this file to customize your reboot / sw reset reasons. Add, remove or + * modify reasons in reboot_reasons[]. + * The reboot reasons will be saved to a secure location in TCDM memory and + * can be read at bootup by e.g. the bootloader. + */ + +#ifndef _REBOOT_REASONS_H +#define _REBOOT_REASONS_H + +/* + * These defines contains the codes that will be written down to a secure + * location before resetting. These values are just dummy values and does not, + * at the moment, affect anything. + */ +#define SW_RESET_NO_ARGUMENT 0x0 +#define SW_RESET_CRASH 0xDEAD +#define SW_RESET_NORMAL 0xc001 + +/* + * The array reboot_reasons[] is used when you want to map a string to a reboot + * reason code + */ +struct reboot_reason { + const char *reason; + unsigned short code; +}; + +extern struct reboot_reason reboot_reasons[]; + +extern unsigned int reboot_reasons_size; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/regulator.h b/arch/arm/mach-ux500/include/mach/regulator.h new file mode 100644 index 00000000000..75ff3340359 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/regulator.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + * License Terms: GNU General Public License v2 + * + */ + +#ifndef MACH_UX500_REGULATOR_H +#define MACH_UX500_REGULATOR_H + +#include <linux/device.h> + +struct ux500_regulator; + +#ifdef CONFIG_REGULATOR +/* + * NOTE! The device will be connected to the correct regulator by this + * new framework. A list with connections will match up dev_name(dev) + * to the specific regulator. This follows the same principle as the + * normal regulator framework. + * + * This framework shall only be used in special cases when a regulator + * has to be enabled/disabled in atomic context. + */ + +/** + * ux500_regulator_get() + * + * @dev: Drivers device struct + * + * Returns a ux500_regulator struct. Shall be used as argument for + * ux500_regulator_atomic_enable/disable calls. + * Return ERR_PTR(-EINVAL) upon no matching regulator found. + */ +struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev); + +/** + * ux500_regulator_atomic_enable() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + * + * The enable/disable functions keep an internal counter, so every + * enable must be paired with an disable in order to turn off regulator. + */ +int ux500_regulator_atomic_enable(struct ux500_regulator *regulator); + +/** + * ux500_regulator_atomic_disable() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + * + */ +int ux500_regulator_atomic_disable(struct ux500_regulator *regulator); + +/** + * ux500_regulator_put() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + */ +void ux500_regulator_put(struct ux500_regulator *regulator); +#else +static inline struct ux500_regulator *__must_check +ux500_regulator_get(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} + +static inline int +ux500_regulator_atomic_enable(struct ux500_regulator *regulator) +{ + return -EINVAL; +} + +static inline int +ux500_regulator_atomic_disable(struct ux500_regulator *regulator) +{ + return -EINVAL; +} + +static inline void ux500_regulator_put(struct ux500_regulator *regulator) +{ +} +#endif + +#endif diff --git a/arch/arm/mach-ux500/include/mach/scu.h b/arch/arm/mach-ux500/include/mach/scu.h new file mode 100644 index 00000000000..a09e86a9d3c --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/scu.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __ASMARM_ARCH_SCU_H +#define __ASMARM_ARCH_SCU_H + +#include <mach/hardware.h> + +#define SCU_BASE U8500_SCU_BASE +/* + * * SCU registers + * */ +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 + +#endif diff --git a/arch/arm/mach-ux500/include/mach/sensors1p.h b/arch/arm/mach-ux500/include/mach/sensors1p.h new file mode 100644 index 00000000000..544e1d8bab5 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/sensors1p.h @@ -0,0 +1,24 @@ + +/* + * Copyright (C) 2009-2010 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * Header file for 1 pin gpio sensors; + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + * + */ + +#ifndef __ASM_ARCH_SFH7741_H +#define __ASM_ARCH_SFH7741_H + +struct sensor_config { + int pin; + int startup_time; /* in ms */ + char regulator[32]; +}; + +struct sensors1p_config { + struct sensor_config hal; + struct sensor_config proximity; +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index e978dbd9e21..4156b10546e 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -14,7 +14,9 @@ #include <asm/mach/time.h> #include <linux/init.h> -extern void __init ux500_map_io(void); +struct sys_timer; +struct amba_device; + extern void __init u5500_map_io(void); extern void __init u8500_map_io(void); @@ -23,13 +25,17 @@ extern void __init u5500_init_devices(void); extern void __init u8500_init_devices(void); extern void __init ux500_init_irq(void); -/* We re-use nomadik_timer for this platform */ -extern void nmdk_timer_init(void); extern void __init amba_add_devices(struct amba_device *devs[], int num); struct sys_timer; -extern struct sys_timer ux500_timer; +extern struct sys_timer u8500_timer; +extern void __init db5500_dma_init(void); +extern void __init db8500_dma_init(void); +extern void __init db8500_uart_init(void); + +extern void __init u8500v2_msp_fixup(void); +extern void __iomem *gic_cpu_base_addr; #define __IO_DEV_DESC(x, sz) { \ .virtual = IO_ADDRESS(x), \ @@ -38,4 +44,11 @@ extern struct sys_timer ux500_timer; .type = MT_DEVICE, \ } +#define __MEM_DEV_DESC(x, sz) { \ + .virtual = IO_ADDRESS(x), \ + .pfn = __phys_to_pfn(x), \ + .length = sz, \ + .type = MT_MEMORY, \ +} + #endif /* __ASM_ARCH_SETUP_H */ diff --git a/arch/arm/mach-ux500/include/mach/shrm.h b/arch/arm/mach-ux500/include/mach/shrm.h new file mode 100644 index 00000000000..6deeeb16ba8 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/shrm.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson + * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson + * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SHM_DRIVER_IF_H__ +#define __SHM_DRIVER_IF_H__ + +#include <linux/device.h> + +/* forward declaration */ +struct shrm_dev; + +typedef void (*rx_cb)(void *data, unsigned int length); +typedef void (*received_msg_handler)(unsigned char l2_header, + void *msg_ptr, unsigned int length, + struct shrm_dev *shrm); + +#endif diff --git a/arch/arm/mach-ux500/include/mach/shrm_config.h b/arch/arm/mach-ux500/include/mach/shrm_config.h new file mode 100644 index 00000000000..a82b35ef77b --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/shrm_config.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson + * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson + * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SHRM_CONFIG_H +#define __SHRM_CONFIG_H + + +/* +Note: modem need to define IPC as a non-cacheable area. +In Cortex R4 MPU requires that base address of NC area is aligned on a +region-sized boundary.On modem side, only 1 NC area can be defined, hence +the whole IPC area must be defined as NC (at least). + +*/ + +/* cache line size = 32bytes*/ +#define SHM_CACHE_LINE 32 +#define SHM_PTR_SIZE 4 + +/* FIFO 0 address configuration */ +/* ---------------------------- */ +/* 128KB */ +#define SHM_FIFO_0_SIZE (128*1024) + + +/* == APE addresses == */ +#ifdef CONFIG_SHRM_V1_UPDATES_VERSION +#define SHM_IPC_BASE_AMCU 0x06F80000 +#else +#define SHM_IPC_BASE_AMCU 0x06000000 +#endif + +/* offset pointers */ +#define SHM_ACFIFO_0_WRITE_AMCU SHM_IPC_BASE_AMCU +#define SHM_ACFIFO_0_READ_AMCU (SHM_ACFIFO_0_WRITE_AMCU + SHM_PTR_SIZE) +#define SHM_CAFIFO_0_WRITE_AMCU (SHM_ACFIFO_0_WRITE_AMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_0_READ_AMCU (SHM_CAFIFO_0_WRITE_AMCU + SHM_PTR_SIZE) +/* FIFO start */ +#define SHM_ACFIFO_0_START_AMCU (SHM_CAFIFO_0_WRITE_AMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_0_START_AMCU (SHM_ACFIFO_0_START_AMCU + SHM_FIFO_0_SIZE) + + +/* == CMT addresses ==*/ +#define SHM_IPC_BASE_CMCU (SHM_IPC_BASE_AMCU+0x08000000) +/* offset pointers */ +#define SHM_ACFIFO_0_WRITE_CMCU SHM_IPC_BASE_CMCU +#define SHM_ACFIFO_0_READ_CMCU (SHM_ACFIFO_0_WRITE_CMCU + SHM_PTR_SIZE) +#define SHM_CAFIFO_0_WRITE_CMCU (SHM_ACFIFO_0_WRITE_CMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_0_READ_CMCU (SHM_CAFIFO_0_WRITE_CMCU + SHM_PTR_SIZE) +/* FIFO*/ +#define SHM_ACFIFO_0_START_CMCU (SHM_CAFIFO_0_WRITE_CMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_0_START_CMCU (SHM_ACFIFO_0_START_CMCU + SHM_FIFO_0_SIZE) + + +/* ADSP addresses*/ +#define SHM_ACFIFO_0_START_ADSP 0x0 +#define SHM_CAFIFO_0_START_ADSP 0x0 +#define SHM_ACFIFO_0_WRITE_ADSP 0x0 +#define SHM_ACFIFO_0_READ_ADSP 0x0 +#define SHM_CAFIFO_0_WRITE_ADSP 0x0 +#define SHM_CAFIFO_0_READ_ADSP 0x0 + +/* FIFO 1 address configuration */ +/* ---------------------------- */ + + +/* FIFO 1 - 4K */ +#define SHM_FIFO_1_SIZE (4*1024) + + +/* == APE addresses == */ +#define SHM_ACFIFO_1_WRITE_AMCU (SHM_CAFIFO_0_START_AMCU + SHM_FIFO_0_SIZE) +#define SHM_ACFIFO_1_READ_AMCU (SHM_ACFIFO_1_WRITE_AMCU + SHM_PTR_SIZE) +#define SHM_CAFIFO_1_WRITE_AMCU (SHM_ACFIFO_1_WRITE_AMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_1_READ_AMCU (SHM_CAFIFO_1_WRITE_AMCU + SHM_PTR_SIZE) +/* FIFO*/ +#define SHM_ACFIFO_1_START_AMCU (SHM_CAFIFO_1_WRITE_AMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_1_START_AMCU (SHM_ACFIFO_1_START_AMCU + SHM_FIFO_1_SIZE) + + +/* == CMT addresses ==*/ +#define SHM_ACFIFO_1_WRITE_CMCU (SHM_CAFIFO_0_START_CMCU + SHM_FIFO_0_SIZE) +#define SHM_ACFIFO_1_READ_CMCU (SHM_ACFIFO_1_WRITE_CMCU + SHM_PTR_SIZE) +#define SHM_CAFIFO_1_WRITE_CMCU (SHM_ACFIFO_1_WRITE_CMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_1_READ_CMCU (SHM_CAFIFO_1_WRITE_CMCU + SHM_PTR_SIZE) +/* FIFO1 start */ +#define SHM_ACFIFO_1_START_CMCU (SHM_CAFIFO_1_WRITE_CMCU + SHM_CACHE_LINE) +#define SHM_CAFIFO_1_START_CMCU (SHM_ACFIFO_1_START_CMCU + SHM_FIFO_1_SIZE) + + +/* ADSP addresses*/ +#define SHM_ACFIFO_1_START_ADSP 0x0 +#define SHM_CAFIFO_1_START_ADSP 0x0 +#define SHM_ACFIFO_1_WRITE_ADSP 0x0 +#define SHM_ACFIFO_1_READ_ADSP 0x0 +#define SHM_CAFIFO_1_WRITE_ADSP 0x0 +#define SHM_CAFIFO_1_READ_ADSP 0x0 + + +#define U8500_SHM_FIFO_APE_COMMON_BASE (SHM_ACFIFO_0_START_AMCU) +#define U8500_SHM_FIFO_CMT_COMMON_BASE (SHM_CAFIFO_0_START_AMCU) +#define U8500_SHM_FIFO_APE_AUDIO_BASE (SHM_ACFIFO_1_START_AMCU) +#define U8500_SHM_FIFO_CMT_AUDIO_BASE (SHM_CAFIFO_1_START_AMCU) + +#endif /* __SHRM_CONFIG_H */ diff --git a/arch/arm/mach-ux500/include/mach/shrm_driver.h b/arch/arm/mach-ux500/include/mach/shrm_driver.h new file mode 100644 index 00000000000..41f518238b3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/shrm_driver.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson + * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson + * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SHRM_DRIVER_H__ +#define __SHRM_DRIVER_H__ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> + +#include <mach/shrm.h> + +#include <linux/cdev.h> + +#define ISA_DEVICES 6 + +#define BOOT_INIT (0) +#define BOOT_INFO_SYNC (1) +#define BOOT_DONE (2) +#define BOOT_UNKNOWN (3) + +/** + * struct shrm_dev - shrm device information + * @ca_wake_irq: CMT wake interrupt number + * @ac_read_notif_0_irq: ape-cmt common channel read notify interrupt + * @ac_read_notif_1_irq: ape-cmt audio channel read notify interrupt + * @ca_msg_pending_notif_0_irq: cmt-ape common channel msg pending interrupt + * @ca_msg_pending_notif_1_irq: cmt-ape audio channel msg pending interrupt + * @intr_base: interrupt base register address + * @ape_common_fifo_base: ape side common channel fifo base addr + * @ape_audio_fifo_base: ape side audio channel fifo base addr + * @cmt_common_fifo_base: cmt side common channel fifo base addr + * @cmt_audio_fifo_base: cmt side audio channel fifo base addr + * @ape_common_fifo_base_phy: physical addr of ape common fifo + * @ape_audio_fifo_base_phy: physical addr of ape audio fifo + * @cmt_common_fifo_base_phy: physical addr of cmt common fifo + * @cmt_audio_fifo_base_phy: physical addr of cmt audio fifo + * @ape_common_fifo_size: ape side common channel fifo size + * @ape_audio_fifo_size: ape side audio channel fifo size + * @cmt_common_fifo_size: cmt side common channel fifo size + * @cmt_audio_fifo_size: cmt side audio channel fifo size + * @netdev_flag_up: flag to indicate up/down of netwok device + * @msr_flag: flag to check on-going MSR sequence + * @ac_common_shared_wptr: ape-cmt common channel write pointer + * @ac_common_shared_rptr: ape-cmt common channel read pointer + * @ca_common_shared_wptr: cmt-ape common channel write pointer + * @ca_common_shared_rptr: cmt-ape common channel read pointer + * @ac_audio_shared_wptr: ape-cmt audio channel write pointer + * @ac_audio_shared_rptr: ape-cmt audio channel read pointer + * @ca_audio_shared_wptr: cmt-ape audio channel write pointer + * @ca_audio_shared_rptr: cmt-ape audio channel read pointer + * @dev: pointer to the driver device + * @ndev: pointer to the network device structure + * @isa_context: pointer to t_isa_driver_sontext dtructure + * @shm_common_ch_wr_wq: work queue for writing to common channel + * @shm_audio_ch_wr_wq: workqueue for writing to audio channel + * @shm_ac_wake_wq: workqueue for receiving ape-cmt wake requests + * @shm_ca_wake_wq: workqueue for receiving cmt-ape wake requests + * @shm_ac_sleep_wq: workqueue for recieving ape-cmt sleep requests + * @send_ac_msg_pend_notify_0: work for handling pending message on common + * channel + * @send_ac_msg_pend_notify_1: work for handling pending message on audio + * channel + * @shm_ac_wake_req: work to send ape-cmt wake request + * @shm_ca_wake_req: work to send cmt-ape wake request + * @shm_ca_sleep_req: work to send cmt-ape sleep request + * @shm_ac_sleep_req: work to send ape-cmt sleep request + */ +struct shrm_dev { + u8 ca_wake_irq; + u8 ac_read_notif_0_irq; + u8 ac_read_notif_1_irq; + u8 ca_msg_pending_notif_0_irq; + u8 ca_msg_pending_notif_1_irq; + void __iomem *intr_base; + void __iomem *ape_common_fifo_base; + void __iomem *ape_audio_fifo_base; + void __iomem *cmt_common_fifo_base; + void __iomem *cmt_audio_fifo_base; + + u32 *ape_common_fifo_base_phy; + u32 *ape_audio_fifo_base_phy; + u32 *cmt_common_fifo_base_phy; + u32 *cmt_audio_fifo_base_phy; + + int ape_common_fifo_size; + int ape_audio_fifo_size; + int cmt_common_fifo_size; + int cmt_audio_fifo_size; + int netdev_flag_up; + int msr_flag; + + void __iomem *ac_common_shared_wptr; + void __iomem *ac_common_shared_rptr; + void __iomem *ca_common_shared_wptr; + void __iomem *ca_common_shared_rptr; + + void __iomem *ac_audio_shared_wptr; + void __iomem *ac_audio_shared_rptr; + void __iomem *ca_audio_shared_wptr; + void __iomem *ca_audio_shared_rptr; + + struct device *dev; + struct net_device *ndev; + struct isa_driver_context *isa_context; + struct workqueue_struct *shm_common_ch_wr_wq; + struct workqueue_struct *shm_audio_ch_wr_wq; + struct workqueue_struct *shm_ac_wake_wq; + struct workqueue_struct *shm_ca_wake_wq; + struct workqueue_struct *shm_ac_sleep_wq; + struct work_struct send_ac_msg_pend_notify_0; + struct work_struct send_ac_msg_pend_notify_1; + struct work_struct shm_ac_wake_req; + struct work_struct shm_ca_wake_req; + struct work_struct shm_ca_sleep_req; + struct work_struct shm_ac_sleep_req; +}; + +/** + * struct queue_element - information to add an element to queue + * @entry: list entry + * @offset: message offset + * @size: message size + * @no: total number of messages + */ +struct queue_element { + struct list_head entry; + u32 offset; + u32 size; + u32 no; +}; + +/** + * struct message_queue - ISI, RPC, AUDIO, SECURITY message queue information + * @fifo_base: pointer to the respective fifo base + * @size: size of the data to be read + * @readptr: fifo read pointer + * @writeptr: fifo write pointer + * @no: total number of messages + * @update_lock: spinlock for protecting the queue read operation + * @q_rp: queue write pointer + * @wq_readable: wait queue head + * @msg_list: message list + * @shrm: pointer to shrm device information structure + */ +struct message_queue { + u8 *fifo_base; + u32 size; + u32 readptr; + u32 writeptr; + u32 no; + spinlock_t update_lock; + atomic_t q_rp; + wait_queue_head_t wq_readable; + struct list_head msg_list; + struct shrm_dev *shrm; +}; + +/** + * struct isadev_context - shrm char interface context + * @dl_queue: structre to store the queue related info + * @device_id: message id(ISI, RPC, AUDIO, SECURITY) + */ +struct isadev_context { + struct message_queue dl_queue; + u8 device_id; + void *addr; +}; + +/** + * struct isa_driver_context - shrm char interface device information + * @is_open: flag to check the usage of queue + * @isadev: pointer to struct t_isadev_context + * @common_tx: spinlock for protecting common channel + * @tx_audio_mutex: mutex for protecting audio channel + * @cdev: character device structre + * @shm_class: pointer to the class structure + */ +struct isa_driver_context { + atomic_t is_open[ISA_DEVICES]; + struct isadev_context *isadev; + spinlock_t common_tx; + struct mutex tx_audio_mutex; + struct cdev cdev; + struct class *shm_class; +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/shrm_net.h b/arch/arm/mach-ux500/include/mach/shrm_net.h new file mode 100644 index 00000000000..a97b276ee15 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/shrm_net.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) ST-Ericsson SA 2009 + * + * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SHRM_NET_H +#define __SHRM_NET_H + +#define SHRM_HLEN 1 +#define PHONET_ALEN 1 + +#define PN_PIPE 0xD9 +#define PN_DEV_HOST 0x00 +#define PN_LINK_ADDR 0x26 +#define PN_TX_QUEUE_LEN 3 + +#define RESOURCE_ID_INDEX 3 +#define SRC_OBJ_INDEX 7 +#define MSG_ID_INDEX 9 +#define PIPE_HDL_INDEX 10 +#define NETLINK_SHRM 20 + +/** + * struct shrm_net_iface_priv - shrm net interface device information + * @shrm_device: pointer to the shrm device information structure + * @iface_num: flag used to indicate the up/down of netdev + */ +struct shrm_net_iface_priv { + struct shrm_dev *shrm_device; + unsigned int iface_num; +}; + +int shrm_register_netdev(struct shrm_dev *shrm_dev_data); +int shrm_net_receive(struct net_device *dev); +int shrm_suspend_netdev(struct net_device *dev); +int shrm_resume_netdev(struct net_device *dev); +int shrm_stop_netdev(struct net_device *dev); +int shrm_restart_netdev(struct net_device *dev); +int shrm_start_netdev(struct net_device *dev); +void shrm_unregister_netdev(struct shrm_dev *shrm_dev_data); + +#endif /* __SHRM_NET_H */ diff --git a/arch/arm/mach-ux500/include/mach/shrm_private.h b/arch/arm/mach-ux500/include/mach/shrm_private.h new file mode 100644 index 00000000000..33a0e18234b --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/shrm_private.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson + * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson + * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __SHRM_PRIVATE_INCLUDED +#define __SHRM_PRIVATE_INCLUDED + +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <mach/shrm.h> + +#define GOP_OUTPUT_REGISTER_BASE (0x0) +#define GOP_SET_REGISTER_BASE (0x4) +#define GOP_CLEAR_REGISTER_BASE (0x8) +#define GOP_TOGGLE_REGISTER_BASE (0xc) + + +#define GOP_AUDIO_AC_READ_NOTIFICATION_BIT (0) +#define GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT (1) +#define GOP_COMMON_AC_READ_NOTIFICATION_BIT (2) +#define GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT (3) +#define GOP_CA_WAKE_REQ_BIT (7) +#define GOP_AUDIO_CA_READ_NOTIFICATION_BIT (23) +#define GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT (24) +#define GOP_COMMON_CA_READ_NOTIFICATION_BIT (25) +#define GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT (26) +#define GOP_CA_WAKE_ACK_BIT (27) + +#define L2_MSG_MAPID_OFFSET (24) +#define L1_MSG_MAPID_OFFSET (28) + +#define SHRM_SLEEP_STATE (0) +#define SHRM_PTR_FREE (1) +#define SHRM_PTR_BUSY (2) +#define SHRM_IDLE (3) + +#define ISI_MESSAGING (0) +#define RPC_MESSAGING (1) +#define AUDIO_MESSAGING (2) +#define SECURITY_MESSAGING (3) +#define COMMON_LOOPBACK_MESSAGING (0xC0) +#define AUDIO_LOOPBACK_MESSAGING (0x80) + +#define COMMON_CHANNEL 0 +#define AUDIO_CHANNEL 1 + +typedef void (*MSG_PENDING_NOTIF)(const u32 Wptr); + +/** + * struct fifo_write_params - parameters used for FIFO write operation. + * @writer_local_rptr: pointer to local read buffer + * @writer_local_wptr: pointer to local write buffer + * @shared_wptr: write pointer shared by cmt and ape + * @shared_rptr: read pointer shared by cmt and ape + * @availablesize: available memory in fifo + * @end_addr_fifo: fifo end addr + * @fifo_virtual_addr: fifo virtual addr + * + * On writting a message to FIFO the same has to be read by the modem before + * writing the next message to the FIFO. In oder to over come this a local + * write and read pointer is used for internal purpose. + */ +struct fifo_write_params { + u32 writer_local_rptr; + u32 writer_local_wptr; + u32 shared_wptr; + u32 shared_rptr; + u32 availablesize; + u32 end_addr_fifo; + u32 *fifo_virtual_addr; + spinlock_t fifo_update_lock; +} ; + +/** + * struct fifo_read_params - parameters used for FIFO read operation + * @reader_local_rptr: pointer to local read buffer + * @reader_local_wptr: pointer to local write buffer + * @shared_wptr: write pointer shared by cmt and ape + * @shared_rptr: read pointer shared by cmt and ape + * @availablesize: available memory in fifo + * @end_addr_fifo: fifo end add + * @fifo_virtual_addr: fifo virtual addr + */ +struct fifo_read_params{ + u32 reader_local_rptr; + u32 reader_local_wptr; + u32 shared_wptr; + u32 shared_rptr; + u32 availablesize; + u32 end_addr_fifo; + u32 *fifo_virtual_addr; + +} ; + +int shrm_protocol_init(struct shrm_dev *shrm, + received_msg_handler common_rx_handler, + received_msg_handler audio_rx_handler); +void shrm_protocol_deinit(struct shrm_dev *shrm); +void shm_fifo_init(struct shrm_dev *shrm); +int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel, + u8 l2header, void *addr, u32 length); +int shm_write_msg(struct shrm_dev *shrm, + u8 l2_header, void *addr, u32 length); + +u8 is_the_only_one_unread_message(struct shrm_dev *shrm, + u8 channel, u32 length); +u8 read_remaining_messages_common(void); +u8 read_remaining_messages_audio(void); +u8 read_one_l2msg_audio(struct shrm_dev *shrm, + u8 *p_l2_msg, u32 *p_len); +u8 read_one_l2msg_common(struct shrm_dev *shrm, + u8 *p_l2_msg, u32 *p_len); +void receive_messages_common(struct shrm_dev *shrm); +void receive_messages_audio(struct shrm_dev *shrm); + +void update_ac_common_local_rptr(struct shrm_dev *shrm); +void update_ac_audio_local_rptr(struct shrm_dev *shrm); +void update_ca_common_local_wptr(struct shrm_dev *shrm); +void update_ca_audio_local_wptr(struct shrm_dev *shrm); +void update_ac_common_shared_wptr(struct shrm_dev *shrm); +void update_ac_audio_shared_wptr(struct shrm_dev *shrm); +void update_ca_common_shared_rptr(struct shrm_dev *shrm); +void update_ca_audio_shared_rptr(struct shrm_dev *shrm); + + +void get_writer_pointers(u8 msg_type, u32 *WriterLocalRptr, \ + u32 *WriterLocalWptr, u32 *SharedWptr); +void get_reader_pointers(u8 msg_type, u32 *ReaderLocalRptr, \ + u32 *ReaderLocalWptr, u32 *SharedRptr); +u8 read_boot_info_req(struct shrm_dev *shrm, + u32 *pConfig, + u32 *pVersion); +void write_boot_info_resp(struct shrm_dev *shrm, u32 Config, + u32 Version); + +void send_ac_msg_pending_notification_0(struct shrm_dev *shrm); +void send_ac_msg_pending_notification_1(struct shrm_dev *shrm); +void ca_msg_read_notification_0(struct shrm_dev *shrm); +void ca_msg_read_notification_1(struct shrm_dev *shrm); + +void set_ca_msg_0_read_notif_send(u8 val); +u8 get_ca_msg_0_read_notif_send(void); +void set_ca_msg_1_read_notif_send(u8 val); +u8 get_ca_msg_1_read_notif_send(void); + +irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr); +irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr); +irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr); +irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr); +irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr); + +void shm_ca_msgpending_0_tasklet(unsigned long); +void shm_ca_msgpending_1_tasklet(unsigned long); +void shm_ac_read_notif_0_tasklet(unsigned long); +void shm_ac_read_notif_1_tasklet(unsigned long); +void shm_ca_wake_req_tasklet(unsigned long); + +u8 get_boot_state(void); + +int get_ca_wake_req_state(void); + +/* shrm character interface */ +int isa_init(struct shrm_dev *shrm); +void isa_exit(struct shrm_dev *shrm); +int add_msg_to_queue(struct message_queue *q, u32 size); +ssize_t isa_read(struct file *filp, char __user *buf, size_t len, + loff_t *ppos); +int get_size_of_new_msg(struct message_queue *q); +int remove_msg_from_queue(struct message_queue *q); +void shrm_char_reset_queues(struct shrm_dev *shrm); +int shrm_get_cdev_index(u8 l2_header); +int shrm_get_cdev_l2header(u8 idx); + +#endif diff --git a/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h b/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h new file mode 100644 index 00000000000..cb2110c3285 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + * + * DB5500-SoC-specific configuration for DMA40 + */ + +#ifndef STE_DMA40_DB5500_H +#define STE_DMA40_DB5500_H + +#define DB5500_DMA_NR_DEV 64 + +enum dma_src_dev_type { + DB5500_DMA_DEV0_SPI0_RX = 0, + DB5500_DMA_DEV1_SPI1_RX = 1, + DB5500_DMA_DEV2_SPI2_RX = 2, + DB5500_DMA_DEV3_SPI3_RX = 3, + DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4, + DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5, + DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6, + DB5500_DMA_DEV7_IRDA_RFS = 7, + DB5500_DMA_DEV8_IRDA_FIFO_RX = 8, + DB5500_DMA_DEV9_MSP0_RX = 9, + DB5500_DMA_DEV10_MSP1_RX = 10, + DB5500_DMA_DEV11_MSP2_RX = 11, + DB5500_DMA_DEV12_UART0_RX = 12, + DB5500_DMA_DEV13_UART1_RX = 13, + DB5500_DMA_DEV14_UART2_RX = 14, + DB5500_DMA_DEV15_UART3_RX = 15, + DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16, + DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17, + DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18, + DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19, + DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20, + DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21, + DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22, + DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23, + DB5500_DMA_DEV24_SDMMC0_RX = 24, + DB5500_DMA_DEV25_SDMMC1_RX = 25, + DB5500_DMA_DEV26_SDMMC2_RX = 26, + DB5500_DMA_DEV27_SDMMC3_RX = 27, + DB5500_DMA_DEV28_SDMMC4_RX = 28, + /* 29 - 32 not used */ + DB5500_DMA_DEV33_SDMMC0_RX = 33, + DB5500_DMA_DEV34_SDMMC1_RX = 34, + DB5500_DMA_DEV35_SDMMC2_RX = 35, + DB5500_DMA_DEV36_SDMMC3_RX = 36, + DB5500_DMA_DEV37_SDMMC4_RX = 37, + DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38, + DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39, + DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40, + DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41, + DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42, + DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43, + DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44, + DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45, + /* 46 not used */ + DB5500_DMA_DEV47_MCDE_RX = 47, + DB5500_DMA_DEV48_CRYPTO1_RX = 48, + /* 49, 50 not used */ + DB5500_DMA_DEV49_I2C1_RX = 51, + DB5500_DMA_DEV50_I2C3_RX = 52, + DB5500_DMA_DEV51_I2C2_RX = 53, + /* 54 - 60 not used */ + DB5500_DMA_DEV61_CRYPTO0_RX = 61, + /* 62, 63 not used */ +}; + +enum dma_dest_dev_type { + DB5500_DMA_DEV0_SPI0_TX = 0, + DB5500_DMA_DEV1_SPI1_TX = 1, + DB5500_DMA_DEV2_SPI2_TX = 2, + DB5500_DMA_DEV3_SPI3_TX = 3, + DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4, + DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5, + DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6, + DB5500_DMA_DEV7_IRRC_TX = 7, + DB5500_DMA_DEV8_IRDA_FIFO_TX = 8, + DB5500_DMA_DEV9_MSP0_TX = 9, + DB5500_DMA_DEV10_MSP1_TX = 10, + DB5500_DMA_DEV11_MSP2_TX = 11, + DB5500_DMA_DEV12_UART0_TX = 12, + DB5500_DMA_DEV13_UART1_TX = 13, + DB5500_DMA_DEV14_UART2_TX = 14, + DB5500_DMA_DEV15_UART3_TX = 15, + DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16, + DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17, + DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18, + DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19, + DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20, + DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21, + DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22, + DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23, + DB5500_DMA_DEV24_SDMMC0_TX = 24, + DB5500_DMA_DEV25_SDMMC1_TX = 25, + DB5500_DMA_DEV26_SDMMC2_TX = 26, + DB5500_DMA_DEV27_SDMMC3_TX = 27, + DB5500_DMA_DEV28_SDMMC4_TX = 28, + /* 29 - 31 not used */ + DB5500_DMA_DEV32_FSMC_TX = 32, + DB5500_DMA_DEV33_SDMMC0_TX = 33, + DB5500_DMA_DEV34_SDMMC1_TX = 34, + DB5500_DMA_DEV35_SDMMC2_TX = 35, + DB5500_DMA_DEV36_SDMMC3_TX = 36, + DB5500_DMA_DEV37_SDMMC4_TX = 37, + DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38, + DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39, + DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40, + DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41, + DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42, + DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43, + DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44, + DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45, + /* 46 not used */ + DB5500_DMA_DEV47_STM_TX = 47, + DB5500_DMA_DEV48_CRYPTO1_TX = 48, + DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49, + DB5500_DMA_DEV50_HASH1_TX = 50, + DB5500_DMA_DEV51_I2C1_TX = 51, + DB5500_DMA_DEV52_I2C3_TX = 52, + DB5500_DMA_DEV53_I2C2_TX = 53, + /* 54, 55 not used */ + DB5500_DMA_MEMCPY_TX_1 = 56, + DB5500_DMA_MEMCPY_TX_2 = 57, + DB5500_DMA_MEMCPY_TX_3 = 58, + DB5500_DMA_MEMCPY_TX_4 = 59, + DB5500_DMA_MEMCPY_TX_5 = 60, + DB5500_DMA_DEV61_CRYPTO0_TX = 61, + DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62, + DB5500_DMA_DEV63_HASH0_TX = 63, +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h b/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h new file mode 100644 index 00000000000..64c494f0836 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) ST-Ericsson SA 2007-2010 + * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + * + * DB8500-SoC-specific configuration for DMA40 + */ +#ifndef STE_DMA40_DB8500_H +#define STE_DMA40_DB8500_H + +#define DB8500_DMA_NR_DEV 64 +/* + * All entries with double names are multiplexed + * and can never be used at the same time. + */ + +enum dma_src_dev_type { + DB8500_DMA_DEV0_SPI0_RX = 0, + DB8500_DMA_DEV1_SD_MMC0_RX = 1, + DB8500_DMA_DEV2_SD_MMC1_RX = 2, + DB8500_DMA_DEV3_SD_MMC2_RX = 3, + DB8500_DMA_DEV4_I2C1_RX = 4, + DB8500_DMA_DEV5_I2C3_RX = 5, + DB8500_DMA_DEV6_I2C2_RX = 6, + DB8500_DMA_DEV7_I2C4_RX = 7, /* Only on V1 and later */ + DB8500_DMA_DEV8_SSP0_RX = 8, + DB8500_DMA_DEV9_SSP1_RX = 9, + DB8500_DMA_DEV10_MCDE_RX = 10, + DB8500_DMA_DEV11_UART2_RX = 11, + DB8500_DMA_DEV12_UART1_RX = 12, + DB8500_DMA_DEV13_UART0_RX = 13, + DB8500_DMA_DEV14_MSP2_RX = 14, + DB8500_DMA_DEV15_I2C0_RX = 15, + DB8500_DMA_DEV16_USB_OTG_IEP_7_15 = 16, + DB8500_DMA_DEV17_USB_OTG_IEP_6_14 = 17, + DB8500_DMA_DEV18_USB_OTG_IEP_5_13 = 18, + DB8500_DMA_DEV19_USB_OTG_IEP_4_12 = 19, + DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0 = 20, + DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1 = 21, + DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2 = 22, + DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3 = 23, + DB8500_DMA_DEV24_SRC_SXA0_RX_TX = 24, + DB8500_DMA_DEV25_SRC_SXA1_RX_TX = 25, + DB8500_DMA_DEV26_SRC_SXA2_RX_TX = 26, + DB8500_DMA_DEV27_SRC_SXA3_RX_TX = 27, + DB8500_DMA_DEV28_SD_MM2_RX = 28, + DB8500_DMA_DEV29_SD_MM0_RX = 29, + DB8500_DMA_DEV30_MSP1_RX = 30, + /* On DB8500v2, MSP3 RX replaces MSP1 RX */ + DB8500_DMA_DEV30_MSP3_RX = 30, + DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX = 31, + DB8500_DMA_DEV32_SD_MM1_RX = 32, + DB8500_DMA_DEV33_SPI2_RX = 33, + DB8500_DMA_DEV34_I2C3_RX2 = 34, + DB8500_DMA_DEV35_SPI1_RX = 35, + DB8500_DMA_DEV36_USB_OTG_IEP_3_11 = 36, + DB8500_DMA_DEV37_USB_OTG_IEP_2_10 = 37, + DB8500_DMA_DEV38_USB_OTG_IEP_1_9 = 38, + DB8500_DMA_DEV39_USB_OTG_IEP_8 = 39, + DB8500_DMA_DEV40_SPI3_RX = 40, + DB8500_DMA_DEV41_SD_MM3_RX = 41, + DB8500_DMA_DEV42_SD_MM4_RX = 42, + DB8500_DMA_DEV43_SD_MM5_RX = 43, + DB8500_DMA_DEV44_SRC_SXA4_RX_TX = 44, + DB8500_DMA_DEV45_SRC_SXA5_RX_TX = 45, + DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX = 46, + DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX = 47, + DB8500_DMA_DEV48_CAC1_RX = 48, + /* 49, 50 and 51 are not used */ + DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4 = 52, + DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5 = 53, + DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6 = 54, + DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7 = 55, + /* 56, 57, 58, 59 and 60 are not used */ + DB8500_DMA_DEV61_CAC0_RX = 61, + /* 62 and 63 are not used */ +}; + +enum dma_dest_dev_type { + DB8500_DMA_DEV0_SPI0_TX = 0, + DB8500_DMA_DEV1_SD_MMC0_TX = 1, + DB8500_DMA_DEV2_SD_MMC1_TX = 2, + DB8500_DMA_DEV3_SD_MMC2_TX = 3, + DB8500_DMA_DEV4_I2C1_TX = 4, + DB8500_DMA_DEV5_I2C3_TX = 5, + DB8500_DMA_DEV6_I2C2_TX = 6, + DB8500_DMA_DEV7_I2C4_TX = 7, /* Only on V1 and later */ + DB8500_DMA_DEV8_SSP0_TX = 8, + DB8500_DMA_DEV9_SSP1_TX = 9, + /* 10 is not used*/ + DB8500_DMA_DEV11_UART2_TX = 11, + DB8500_DMA_DEV12_UART1_TX = 12, + DB8500_DMA_DEV13_UART0_TX = 13, + DB8500_DMA_DEV14_MSP2_TX = 14, + DB8500_DMA_DEV15_I2C0_TX = 15, + DB8500_DMA_DEV16_USB_OTG_OEP_7_15 = 16, + DB8500_DMA_DEV17_USB_OTG_OEP_6_14 = 17, + DB8500_DMA_DEV18_USB_OTG_OEP_5_13 = 18, + DB8500_DMA_DEV19_USB_OTG_OEP_4_12 = 19, + DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0 = 20, + DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1 = 21, + DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2 = 22, + DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3 = 23, + DB8500_DMA_DEV24_DST_SXA0_RX_TX = 24, + DB8500_DMA_DEV25_DST_SXA1_RX_TX = 25, + DB8500_DMA_DEV26_DST_SXA2_RX_TX = 26, + DB8500_DMA_DEV27_DST_SXA3_RX_TX = 27, + DB8500_DMA_DEV28_SD_MM2_TX = 28, + DB8500_DMA_DEV29_SD_MM0_TX = 29, + DB8500_DMA_DEV30_MSP1_TX = 30, + DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX = 31, + DB8500_DMA_DEV32_SD_MM1_TX = 32, + DB8500_DMA_DEV33_SPI2_TX = 33, + DB8500_DMA_DEV34_I2C3_TX2 = 34, + DB8500_DMA_DEV35_SPI1_TX = 35, + DB8500_DMA_DEV36_USB_OTG_OEP_3_11 = 36, + DB8500_DMA_DEV37_USB_OTG_OEP_2_10 = 37, + DB8500_DMA_DEV38_USB_OTG_OEP_1_9 = 38, + DB8500_DMA_DEV39_USB_OTG_OEP_8 = 39, + DB8500_DMA_DEV40_SPI3_TX = 40, + DB8500_DMA_DEV41_SD_MM3_TX = 41, + DB8500_DMA_DEV42_SD_MM4_TX = 42, + DB8500_DMA_DEV43_SD_MM5_TX = 43, + DB8500_DMA_DEV44_DST_SXA4_RX_TX = 44, + DB8500_DMA_DEV45_DST_SXA5_RX_TX = 45, + DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX = 46, + DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX = 47, + DB8500_DMA_DEV48_CAC1_TX = 48, + DB8500_DMA_DEV49_CAC1_TX_HAC1_TX = 49, + DB8500_DMA_DEV50_HAC1_TX = 50, + DB8500_DMA_MEMCPY_TX_0 = 51, + DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4 = 52, + DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5 = 53, + DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6 = 54, + DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7 = 55, + DB8500_DMA_MEMCPY_TX_1 = 56, + DB8500_DMA_MEMCPY_TX_2 = 57, + DB8500_DMA_MEMCPY_TX_3 = 58, + DB8500_DMA_MEMCPY_TX_4 = 59, + DB8500_DMA_MEMCPY_TX_5 = 60, + DB8500_DMA_DEV61_CAC0_TX = 61, + DB8500_DMA_DEV62_CAC0_TX_HAC0_TX = 62, + DB8500_DMA_DEV63_HAC0_TX = 63, +}; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io.h b/arch/arm/mach-ux500/include/mach/ste_audio_io.h new file mode 100644 index 00000000000..a8a617b8392 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ste_audio_io.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef _U8500_STE_AUDIO_IO_H_ +#define _U8500_STE_AUDIO_IO_H_ + + +struct ab8500_audio_platform_data { + int (*ste_gpio_altf_init) (void); + int (*ste_gpio_altf_exit) (void); +}; + +#endif /* _U8500_STE_AUDIO_IO_H_ */ diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h new file mode 100644 index 00000000000..e04734d65a5 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h @@ -0,0 +1,234 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2. + */ + +#ifndef _AUDIOIO_IOCTL_H_ +#define _AUDIOIO_IOCTL_H_ + + +#define AUDIOIO_IOC_MAGIC 'N' +#define AUDIOIO_READ_REGISTER _IOWR(AUDIOIO_IOC_MAGIC, 1,\ + struct audioio_data_t) +#define AUDIOIO_WRITE_REGISTER _IOW(AUDIOIO_IOC_MAGIC, 2,\ + struct audioio_data_t) +#define AUDIOIO_PWR_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 3,\ + struct audioio_pwr_ctrl_t) +#define AUDIOIO_PWR_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 4,\ + struct audioio_pwr_ctrl_t) +#define AUDIOIO_LOOP_CTRL _IOW(AUDIOIO_IOC_MAGIC, 5,\ + struct audioio_loop_ctrl_t) +#define AUDIOIO_LOOP_STS _IOR(AUDIOIO_IOC_MAGIC, 6,\ + struct audioio_loop_ctrl_t) +#define AUDIOIO_GET_TRNSDR_GAIN_CAPABILITY _IOR(AUDIOIO_IOC_MAGIC, 7,\ + struct audioio_get_gain_t) +#define AUDIOIO_GAIN_CAP_LOOP _IOR(AUDIOIO_IOC_MAGIC, 8,\ + struct audioio_gain_loop_t) +#define AUDIOIO_SUPPORT_LOOP _IOR(AUDIOIO_IOC_MAGIC, 9,\ + struct audioio_support_loop_t) +#define AUDIOIO_GAIN_DESC_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 10,\ + struct audioio_gain_desc_trnsdr_t) +#define AUDIOIO_GAIN_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 11,\ + struct audioio_gain_ctrl_trnsdr_t) +#define AUDIOIO_GAIN_QUERY_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 12,\ + struct audioio_gain_ctrl_trnsdr_t) +#define AUDIOIO_MUTE_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 13,\ + struct audioio_mute_trnsdr_t) +#define AUDIOIO_MUTE_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 14,\ + struct audioio_mute_trnsdr_t) +#define AUDIOIO_FADE_CTRL _IOW(AUDIOIO_IOC_MAGIC, 15,\ + struct audioio_fade_ctrl_t) +#define AUDIOIO_BURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 16,\ + struct audioio_burst_ctrl_t) +#define AUDIOIO_READ_ALL_ACODEC_REGS_CTRL _IOW(AUDIOIO_IOC_MAGIC, 17,\ + struct audioio_read_all_acodec_reg_ctrl_t) +#define AUDIOIO_FSBITCLK_CTRL _IOW(AUDIOIO_IOC_MAGIC, 18,\ + struct audioio_fsbitclk_ctrl_t) +#define AUDIOIO_PSEUDOBURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 19,\ + struct audioio_pseudoburst_ctrl_t) +#define AUDIOIO_AUDIOCODEC_PWR_CTRL _IOW(AUDIOIO_IOC_MAGIC, 20, \ + struct audioio_acodec_pwr_ctrl_t) +#define AUDIOIO_FIR_COEFFS_CTRL _IOW(AUDIOIO_IOC_MAGIC, 21, \ + struct audioio_fir_coefficients_t) +#define AUDIOIO_LOOP_GAIN_DESC_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 22,\ + struct audioio_gain_desc_trnsdr_t) +#define AUDIOIO_CLK_SELECT_CTRL _IOR(AUDIOIO_IOC_MAGIC, 23,\ + struct audioio_clk_select_t) +/* audio codec channel ids */ +#define EAR_CH 0 +#define HS_CH 1 +#define IHF_CH 2 +#define VIBL_CH 3 +#define VIBR_CH 4 +#define MIC1A_CH 5 +#define MIC1B_CH 6 +#define MIC2_CH 7 +#define LIN_CH 8 +#define DMIC12_CH 9 +#define DMIC34_CH 10 +#define DMIC56_CH 11 +#define MULTI_MIC_CH 12 +#define FMRX_CH 13 +#define FMTX_CH 14 +#define BLUETOOTH_CH 15 + +#define FIRST_CH EAR_CH +#define LAST_CH BLUETOOTH_CH + +#define MAX_NO_TRANSDUCERS 16 +#define STE_AUDIOIO_MAX_COEFFICIENTS 128 +#define MAX_NO_OF_LOOPS 19 + +#define AUDIOIO_TRUE 1 +#define AUDIOIO_FALSE 0 + +enum AUDIOIO_CLK_TYPE { + AUDIOIO_ULP_CLK, + AUDIOIO_SYS_CLK +}; + +enum AUDIOIO_COMMON_SWITCH { + AUDIOIO_COMMON_OFF = 0, + AUDIOIO_COMMON_ON, + AUDIOIO_COMMON_ALLCHANNEL_UNSUPPORTED = 0xFFFF +}; + +enum AUDIOIO_HAL_HW_LOOPS { + AUDIOIO_NO_LOOP = 0x0, + AUDIOIO_SIDETONE_LOOP = 0x01, + AUDIOIO_MIC1B_TO_HFL = 0x02, + AUDIOIO_MIC1B_TO_HFR = 0x04, + AUDIOIO_MIC1B_TO_EAR = 0x08, + AUDIOIO_MIC1A_TO_HSL = 0x10, + AUDIOIO_MIC1A_TO_HSR = 0x20, + AUDIOIO_MIC1A_TO_HSR_HSL = 0x40, + AUDIOIO_LINEIN_TO_HF = 0x80, + AUDIOIO_DMIC12_TO_HSR_HSL = 0x100, + AUDIOIO_DIC34_TO_HSR_HSL = 0x200, + AUDIOIO_DIC56_TO_HSR_HSL = 0x400, + AUDIOIO_DMIC12_TO_ST = 0x800, + AUDIOIO_DMIC34_TO_ST = 0x1000, + AUDIOIO_DMIC56_TO_ST = 0x2000, + AUDIOIO_ANC_LOOP = 0x4000, + AUDIOIO_LININ_HS = 0x8000, + AUDIOIO_LININL_HSL = 0x10000, + AUDIOIO_LININ_HSR = 0x20000 +}; + + +enum AUDIOIO_FADE_PERIOD { + e_FADE_00, + e_FADE_01, + e_FADE_10, + e_FADE_11 +}; + +enum AUDIOIO_CH_INDEX { + e_CHANNEL_1 = 0x01, + e_CHANNEL_2 = 0x02, + e_CHANNEL_3 = 0x04, + e_CHANNEL_4 = 0x08, + e_CHANNEL_ALL = 0x0f +}; + +struct audioio_data_t { + unsigned char block; + unsigned char addr; + unsigned char data; +}; + +struct audioio_pwr_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; + int channel_type; + enum AUDIOIO_CH_INDEX channel_index; +}; + +struct audioio_acodec_pwr_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; +}; + +struct audioio_loop_ctrl_t { + enum AUDIOIO_HAL_HW_LOOPS hw_loop; + enum AUDIOIO_COMMON_SWITCH ctrl_switch; + int channel_type; + enum AUDIOIO_CH_INDEX channel_index; + int loop_gain; +}; + +struct audioio_get_gain_t { + unsigned int num_channels; + unsigned short max_num_gain; +}; + +struct audioio_gain_loop_t { + int channel_type; + unsigned short num_loop; + unsigned short max_gains; +}; + +struct audioio_support_loop_t { + int channel_type; + unsigned short spprtd_loop_index; +}; + +struct audioio_gain_desc_trnsdr_t { + enum AUDIOIO_CH_INDEX channel_index; + int channel_type; + unsigned short gain_index; + int min_gain; + int max_gain; + unsigned int gain_step; +}; + +struct audioio_gain_ctrl_trnsdr_t { + enum AUDIOIO_CH_INDEX channel_index; + int channel_type; + unsigned short gain_index; + int gain_value; + unsigned int linear; +}; + +struct audioio_mute_trnsdr_t { + int channel_type; + enum AUDIOIO_CH_INDEX channel_index; + enum AUDIOIO_COMMON_SWITCH ctrl_switch; +}; + +struct audioio_fade_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; + enum AUDIOIO_FADE_PERIOD fade_period; + int channel_type; + enum AUDIOIO_CH_INDEX channel_index; +}; + +struct audioio_burst_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; + int channel_type; + int burst_fifo_interrupt_sample_count; + int burst_fifo_length;/* BFIFOTx */ + int burst_fifo_switch_frame; + int burst_fifo_sample_number; +}; + +struct audioio_read_all_acodec_reg_ctrl_t { + unsigned char data[200]; +}; + +struct audioio_fsbitclk_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; +}; + +struct audioio_pseudoburst_ctrl_t { + enum AUDIOIO_COMMON_SWITCH ctrl_switch; +}; + +struct audioio_fir_coefficients_t { + unsigned char start_addr; + unsigned short coefficients[STE_AUDIOIO_MAX_COEFFICIENTS]; +}; + +struct audioio_clk_select_t { + enum AUDIOIO_CLK_TYPE required_clk; +}; +#endif diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h new file mode 100644 index 00000000000..6b6a558e90a --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h @@ -0,0 +1,37 @@ +/* +* Overview: +* Header File defining vibrator kernel space interface +* +* Copyright (C) 2010 ST Ericsson +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#ifndef _STE_AUDIO_IO_VIBRATOR_H_ +#define _STE_AUDIO_IO_VIBRATOR_H_ + +/* Client definitions which can use vibrator, defined as bitmask */ +#define STE_AUDIOIO_CLIENT_AUDIO_L 1 +#define STE_AUDIOIO_CLIENT_AUDIO_R 2 +#define STE_AUDIOIO_CLIENT_FF_VIBRA 4 +#define STE_AUDIOIO_CLIENT_TIMED_VIBRA 8 + +/* + * Define vibrator's maximum speed allowed + * Duty cycle supported by vibrator's PWM is 0-100 + */ +#define STE_AUDIOIO_VIBRATOR_MAX_SPEED 100 + +/* Vibrator speed structure */ +struct ste_vibra_speed { + unsigned char positive; + unsigned char negative; +}; + +/* Vibrator control function - uses PWM source */ +int ste_audioio_vibrator_pwm_control(int client, + struct ste_vibra_speed left_speed, struct ste_vibra_speed right_speed); + +#endif diff --git a/arch/arm/mach-ux500/include/mach/stm_musb.h b/arch/arm/mach-ux500/include/mach/stm_musb.h new file mode 100644 index 00000000000..8fe93dd07b3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/stm_musb.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2009 STMicroelectronics + * Copyright (C) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __MUSB_U8500_H__ +#define __MUSB_U8500_H__ + +#include <mach/hardware.h> + +/* + * TODO: We don't want dependencies from a generic driver (power/ab8500_bm) + * towards a enum in machine specific header files. This should be changed + */ +enum ab8500_usb_state { + AB8500_BM_USB_STATE_RESET_HS, /* HighSpeed Reset */ + AB8500_BM_USB_STATE_RESET_FS, /* FullSpeed/LowSpeed Reset */ + AB8500_BM_USB_STATE_CONFIGURED, + AB8500_BM_USB_STATE_SUSPEND, + AB8500_BM_USB_STATE_RESUME, + AB8500_BM_USB_STATE_MAX, +}; + +/* + * U8500-specific definitions + */ + +/* + * Top-level Control and Status Registers + */ +#define OTG_DMASEL 0x200 /* OTG DMA Selector Register */ +#define OTG_TOPCTRL 0x204 /* OTG Top Control Register */ + +/* + * ULPI-specific Registers + */ +#define OTG_UVBCTRL 0x70 /* OTG ULPI VBUS Control Register*/ +#define OTG_UCKIT 0x71 /* OTG ULPI CarKit Control Register*/ +#define OTG_UINTMASK 0x72 /* OTG ULPI INT Mask Register*/ +#define OTG_UINTSRC 0x73 /* OTG ULPI INT Source Register*/ +#define OTG_UREGDATA 0x74 /* OTG ULPI Reg Data Register*/ +#define OTG_UREGADDR 0x75 /* OTG ULPI Reg Address Register*/ +#define OTG_UREGCTRL 0x76 /* OTG ULPI Reg Control Register*/ +#define OTG_URAWDATA 0x77 /* OTG ULPI Raw Data Register*/ + +/* + * OTG Top Control Register Bits + */ +#define OTG_TOPCTRL_MODE_ULPI (1 << 0) /* Activate ULPI interface*/ +#define OTG_TOPCTRL_UDDR (1 << 1) /* Activate ULPI double-data rate mode */ +#define OTG_TOPCTRL_SRST (1 << 2) /* OTG core soft reset*/ +#define OTG_TOPCTRL_XGATE (1 << 3) /* Activate transceiver clock*/ +#define OTG_TOPCTRL_I2C_OFF (1 << 4) /* Switch off I2C controller*/ +#define OTG_TOPCTRL_HDEV (1 << 5) /* Select host mode with FS interface*/ +#define OTG_TOPCTRL_VBUSLO (1 << 6) /* Enable VBUS for FS transceivers*/ + +/* + * OTG ULPI VBUS Control Register Bits + */ +#define OTG_UVBCTRL_EXTVB (1 << 0) /* Use External VBUS*/ +#define OTG_UVBCTRL_EXTVI (1 << 1) /* Use External VBUS Indicator*/ + +/* + * OTG ULPI Reg Control Register Bits + */ +#define OTG_UREGCTRL_REGREQ (1 << 0) /* Request ULPI register access */ +#define OTG_UREGCTRL_REGCMP (1 << 1) /* ULPI register access completion flag */ +#define OTG_UREGCTRL_URW (1 << 2) /* Request read from register access */ + +/* + * STULPI01/STULPI05-specific definitions + */ + +/* + * Registers accessors (different offsets for read/write/set/clear functions) + */ +#define ULPI_REG_READ(x) (x + 0) +#define ULPI_REG_WRITE(x) (x + 0) +#define ULPI_REG_SET(x) (x + 1) +#define ULPI_REG_CLEAR(x) (x + 2) + +/* + * STULPI01/STULPI05 Registers + */ +#define ULPI_VIDLO 0x00 /* Vendor ID Low (Read Only) */ +#define ULPI_VIDHI 0x01 /* Vendor ID High (Read Only) */ +#define ULPI_PIDLO 0x02 /* Product ID Low (Read Only) */ +#define ULPI_PIDHI 0x03 /* Product ID High (Read Only) */ +#define ULPI_FCTRL 0x04 /* Function Control Register */ +#define ULPI_ICTRL 0x07 /* Interface Control Register */ +#define ULPI_OCTRL 0x0A /* OTG Control Register */ +#define ULPI_INTENRIS 0x0D /* Interrupt Enable Rising */ +#define ULPI_INTENFAL 0x10 /* Interrupt Enable Falling */ +#define ULPI_INTSTATU 0x13 /* Interrupt Status (Read Only) */ +#define ULPI_INTLATCH 0x14 /* Interrupt Latch (Read Only) */ +#define ULPI_DEBUG 0x15 /* Debug Register (Read Only) */ +#define ULPI_SCRATCH 0x16 /* Scratch Register */ +#define ULPI_CCTRL 0x19 /* Carkit Control Register */ +#define ULPI_PCTRL 0x3D /* Power Control Register */ +#define ULPI_ULINKSTAT 0x39 /* USB Link Status & Control Register */ + +/* + * Vendor and Product IDs + */ +#define ULPI_VIDLO_VALUE 0x83 /*Vendor ID Low*/ +#define ULPI_VIDHI_VALUE 0x04 /*Vendor ID High*/ +#define ULPI_PIDLO_VALUE 0x4B /*Product ID Low*/ +#define ULPI_PIDHI_VALUE 0x4F /*Product ID High*/ + +/** + * STULPI Function Control Register Bits + */ +#define ULPI_FCTRL_HSEN (0 << 0) +#define ULPI_FCTRL_FSEN (1 << 0) +#define ULPI_FCTRL_LSEN (2 << 0) +#define ULPI_FCTRL_FSLSEN (3 << 0) +#define ULPI_FCTRL_TSELECT (1 << 2) +#define ULPI_FCTRL_OM_NORM (0 << 3) +#define ULPI_FCTRL_OM_NONDRIV (1 << 3) +#define ULPI_FCTRL_OM_NRZIDIS (2 << 3) +#define ULPI_FCTRL_OM_NOSYNC (3 << 3) +#define ULPI_FCTRL_RESET (1 << 5) +#define ULPI_FCTRL_NOSUSPEND (1 << 6) + +/* + * STULPI Interface Control Register Bits + */ +#define ULPI_ICTRL_6PINSERIAL (1 << 0) +#define ULPI_ICTRL_3PINSERIAL (1 << 1) +#define ULPI_ICTRL_CARKITEN (1 << 2) +#define ULPI_ICTRL_PSCLOCKEN (1 << 3) +#define ULPI_ICTRL_VBUSINV (1 << 5) +#define ULPI_ICTRL_IPASSTHRU (1 << 6) +#define ULPI_ICTRL_IPROTDIS (1 << 7) + +/* + * STULPI OTG Control Register Bits + */ +#define ULPI_OCTRL_IDPULLUP (1 << 0) +#define ULPI_OCTRL_DPPULLDOWN (1 << 1) +#define ULPI_OCTRL_DMPULLDOWN (1 << 2) +#define ULPI_OCTRL_DISCHRGVBUS (1 << 3) +#define ULPI_OCTRL_CHRGVBUS (1 << 4) +#define ULPI_OCTRL_DRVVBUS (1 << 5) +#define ULPI_OCTRL_DRVVBUSEXT (1 << 6) +#define ULPI_OCTRL_EXTVBUSIND (1 << 7) + +/* + * STULPI USB Link Status & Control Register + */ + +/* function prototypes */ +void ab8500_bm_usb_state_changed_wrapper(u8 bm_usb_state); + +#endif/* __MUSB_U8500_H__ */ diff --git a/arch/arm/mach-ux500/include/mach/suspend.h b/arch/arm/mach-ux500/include/mach/suspend.h new file mode 100644 index 00000000000..582fa324df3 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/suspend.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef __MACH_SUSPEND_H +#define __MACH_SUSPEND_H + +void suspend_block_sleep(void); +void suspend_unblock_sleep(void); +void suspend_set_pins_force_fn(void (*force)(void), void (*force_mux)(void)); + +#endif /* __MACH_SUSPEND_H */ diff --git a/arch/arm/mach-ux500/include/mach/system.h b/arch/arm/mach-ux500/include/mach/system.h index c0cd8006f1a..ec056d9198c 100644 --- a/arch/arm/mach-ux500/include/mach/system.h +++ b/arch/arm/mach-ux500/include/mach/system.h @@ -8,6 +8,9 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#include <mach/prcmu-fw-api.h> +#include <mach/reboot_reasons.h> + static inline void arch_idle(void) { /* @@ -19,7 +22,10 @@ static inline void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { - /* yet to be implemented - TODO */ +#ifdef CONFIG_UX500_SOC_DB8500 + /* Call the PRCMU reset API (w/o reset reason code) */ + prcmu_system_reset(SW_RESET_NO_ARGUMENT); +#endif } #endif diff --git a/arch/arm/mach-ux500/include/mach/tc35893-keypad.h b/arch/arm/mach-ux500/include/mach/tc35893-keypad.h new file mode 100644 index 00000000000..e585a2029f5 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/tc35893-keypad.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License, version 2 + * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> for ST-Ericsson + */ + +#ifndef __TC35893_KEYPAD_H +#define __TC35893_KEYPAD_H + +/* + * Keypad related platform specific constants + * These values may be modified for fine tuning + */ +#define TC_KPD_ROWS 0x8 +#define TC_KPD_COLUMNS 0x8 +#define TC_KPD_DEBOUNCE_PERIOD 0xA3 +#define TC_KPD_SETTLE_TIME 0xA3 + +/** + * struct tc35893_platform_data - data structure for platform specific data + * @keymap_data: matrix scan code table for keycodes + * @krow: mask for available rows, value is 0xFF + * @kcol: mask for available columns, value is 0xFF + * @debounce_period: platform specific debounce time + * @settle_time: platform specific settle down time + * @irqtype: type of interrupt, falling or rising edge + * @irq: irq no, + * @enable_wakeup: specifies if keypad event can wake up system from sleep + * @no_autorepeat: flag for auto repetition + */ +struct tc35893_platform_data { + struct matrix_keymap_data *keymap_data; + u8 krow; + u8 kcol; + u8 debounce_period; + u8 settle_time; + unsigned long irqtype; + int irq; + bool enable_wakeup; + bool no_autorepeat; +}; + +#endif /*__TC35893_KEYPAD_H*/ diff --git a/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h b/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h new file mode 100644 index 00000000000..6978b7314c5 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h @@ -0,0 +1,48 @@ +/* + * Data types and interface for TEE application for starting the modem. + * + * Copyright (C) ST-Ericsson SA 2010 + * Author: Shujuan Chen <shujuan.chen@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef TEE_TA_START_MODEM_H +#define TEE_TA_START_MODEM_H + +#define COMMAND_ID_START_MODEM 0x00000001 + +#define UUID_TEE_TA_START_MODEM_LOW 0x8AD94107 +#define UUID_TEE_TA_START_MODEM_MID 0x6E50 +#define UUID_TEE_TA_START_MODEM_HIGH 0x418E +#define UUID_TEE_TA_START_MODEM_CLOCKSEQ \ + {0xB1, 0x14, 0x75, 0x7D, 0x60, 0x21, 0xBD, 0x36} + +struct mcore_segment_descr { + void *segment; + void *hash; + u32 size; +}; + +struct access_image_descr { + void *elf_hdr; + void *pgm_hdr_tbl; + void *signature; + unsigned long nbr_segment; + struct mcore_segment_descr *descr; +}; + +/* TODO: To be redefined with only info needed by Secure world. */ +struct tee_ta_start_modem { + void *access_mem_start; + u32 shared_mem_size; + u32 access_private_mem_size; + struct access_image_descr access_image_descr; +}; + +/** + * This is the function to handle the modem release. + */ +int tee_ta_start_modem(struct tee_ta_start_modem *data); + +#endif + diff --git a/arch/arm/mach-ux500/include/mach/timex.h b/arch/arm/mach-ux500/include/mach/timex.h index d0942c17401..c100e3dc2ef 100644 --- a/arch/arm/mach-ux500/include/mach/timex.h +++ b/arch/arm/mach-ux500/include/mach/timex.h @@ -2,5 +2,8 @@ #define __ASM_ARCH_TIMEX_H #define CLOCK_TICK_RATE 110000000 +#ifndef CONFIG_UX500_SOC_DB5500 +#define ARCH_HAS_READ_CURRENT_TIMER +#endif #endif diff --git a/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h b/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h new file mode 100644 index 00000000000..0575bbdb730 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h @@ -0,0 +1,284 @@ +/* Header file for u8500 audiocodec specific data structures, enums + * and private & public functions. + * Author: Deepak Karda + * Copyright (C) 2009 ST-Ericsson Pvt. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _U8500_ACODEC_AB8500_H_ +#define _U8500_ACODEC_AB8500_H_ + +#include <mach/ab8500.h> +#include <linux/i2s/i2s.h> + +#ifdef CONFIG_U8500_AB8500_CUT10 +#include <mach/ab8500_codec_v1_0.h> +//#include <mach/ab8500_codec_p_v1_0.h> +#else /*CONFIG_U8500_4500_ED */ +#include <mach/ab8500_codec.h> +#include <mach/ab8500_codec_p.h> +#endif + +#define NUMBER_OUTPUT_DEVICE 5 +#define NUMBER_INPUT_DEVICE 13 +#define NUMBER_LOOPBACK_STATE 2 +#define NUMBER_SWITCH_STATE 2 +#define NUMBER_POWER_STATE 2 +#define NUMBER_TDM_MODE_STATE 2 +#define NUMBER_DIRECT_RENDERING_STATE 2 +#define NUMBER_PCM_RENDERING_STATE 3 + +#define CODEC_MUTE 0x20 +#define DEFAULT_VOLUME 0x64 +#define DEFAULT_GAIN 0x32 +#define VOL_MAX 0x64 +#define VOL_MIN 0x00 +#define DEFAULT_OUTPUT_DEVICE AB8500_CODEC_DEST_HEADSET +#define DEFAULT_INPUT_DEVICE AB8500_CODEC_SRC_D_MICROPHONE_1 +#define DEFAULT_LOOPBACK_STATE DISABLE +#define DEFAULT_SWITCH_STATE DISABLE +#define DEFAULT_TDM8_CH_MODE_STATE DISABLE +#define DEFAULT_DIRECT_RENDERING_STATE DISABLE +#define DEFAULT_BURST_FIFO_STATE RENDERING_DISABLE +#define DEFAULT_FM_PLAYBACK_STATE RENDERING_DISABLE +#define DEFAULT_FM_TX_STATE RENDERING_DISABLE + +#define MIN_RATE_PLAYBACK 48000 +#define MAX_RATE_PLAYBACK 48000 +#define MIN_RATE_CAPTURE 48000 +#define MAX_RATE_CAPTURE 48000 +#define MAX_NO_OF_RATES 1 + +#define ALSA_MSP_BT_NUM 0 +#define ALSA_MSP_PCM_NUM 1 +#define ALSA_MSP_HDMI_NUM 2 + +#define I2S_CLIENT_MSP0 0 +#define I2S_CLIENT_MSP1 1 +#define I2S_CLIENT_MSP2 2 + +typedef enum { + DISABLE, + ENABLE +} t_u8500_bool_state; + +typedef enum { + RENDERING_DISABLE, + RENDERING_ENABLE, + RENDERING_PENDING +} t_u8500_pmc_rendering_state; + +typedef enum { + ACODEC_CONFIG_REQUIRED, + ACODEC_CONFIG_NOT_REQUIRED +} t_u8500_acodec_config_need; + +typedef enum { + CLASSICAL_MODE, + TDM_8_CH_MODE +} t_u8500_mode; + +typedef struct { + unsigned int left_volume; + unsigned int right_volume; + unsigned int mute_state; + t_u8500_bool_state power_state; +} u8500_io_dev_config_t; + +typedef enum { + NO_USER = 0, + USER_ALSA = 2, /*To make it equivalent to user id for MSP */ + USER_SAA, +} t_acodec_user; + +typedef struct { + u8500_io_dev_config_t output_config[NUMBER_OUTPUT_DEVICE]; + u8500_io_dev_config_t input_config[NUMBER_INPUT_DEVICE]; + //t_acodec_user user; + t_acodec_user cur_user; +} t_u8500_codec_system_context; + +typedef enum { + T_CODEC_SAMPLING_FREQ_48KHZ = 48, +} acodec_sample_frequency; + +struct acodec_configuration { + t_ab8500_codec_direction direction; + acodec_sample_frequency input_frequency; + acodec_sample_frequency output_frequency; + codec_msp_srg_clock_sel_type mspClockSel; + codec_msp_in_clock_freq_type mspInClockFreq; + u32 channels; + t_acodec_user user; + t_u8500_acodec_config_need acodec_config_need; + t_u8500_bool_state direct_rendering_mode; + t_u8500_bool_state tdm8_ch_mode; + t_u8500_bool_state digital_loopback; + void (*handler) (void *data); + void *tx_callback_data; + void *rx_callback_data; +}; + +typedef enum { + ACODEC_DISABLE_ALL, + ACODEC_DISABLE_TRANSMIT, + ACODEC_DISABLE_RECEIVE, +} t_acodec_disable; + +struct i2sdrv_data { + struct i2s_device *i2s; + spinlock_t i2s_lock; + /* buffer is NULL unless this device is open (users > 0) */ + int flag; + u32 tx_status; + u32 rx_status; +}; + +#define MAX_I2S_CLIENTS 3 //0=BT, 1=ACODEC, 2=HDMI + +/*extern t_ab8500_codec_error u8500_acodec_set_volume(int input_vol_left, + int input_vol_right, + int output_vol_left, + int output_vol_right, t_acodec_user user);*/ + +extern t_ab8500_codec_error u8500_acodec_open(int client_id, int stream_id); +//extern t_ab8500_codec_error u8500_acodec_pause_transfer(void); +//extern t_ab8500_codec_error u8500_acodec_unpause_transfer(void); +extern t_ab8500_codec_error u8500_acodec_send_data(int client_id, void *data, + size_t bytes, int dma_flag); +extern t_ab8500_codec_error u8500_acodec_receive_data(int client_id, void *data, + size_t bytes, + int dma_flag); +extern t_ab8500_codec_error u8500_acodec_close(int client_id, + t_acodec_disable flag); +extern t_ab8500_codec_error u8500_acodec_tx_rx_data(int client_id, + void *tx_data, + size_t tx_bytes, + void *rx_data, + size_t rx_bytes, + int dma_flag); + +extern t_ab8500_codec_error u8500_acodec_set_output_volume(t_ab8500_codec_dest + dest_device, + int left_volume, + int right_volume, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_get_output_volume(t_ab8500_codec_dest + dest_device, + int *p_left_volume, + int *p_right_volume, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_set_input_volume(t_ab8500_codec_src + src_device, + int left_volume, + int right_volume, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_get_input_volume(t_ab8500_codec_src + src_device, + int *p_left_volume, + int *p_right_volume, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_toggle_analog_lpbk(t_u8500_bool_state + lpbk_state, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_toggle_digital_lpbk(t_u8500_bool_state + lpbk_state, + t_ab8500_codec_dest + dest_device, + t_ab8500_codec_src + src_device, + t_acodec_user user, + t_u8500_bool_state + tdm8_ch_mode); + +extern t_ab8500_codec_error +u8500_acodec_toggle_playback_mute_control(t_ab8500_codec_dest dest_device, + t_u8500_bool_state mute_state, + t_acodec_user user); +extern t_ab8500_codec_error +u8500_acodec_toggle_capture_mute_control(t_ab8500_codec_src src_device, + t_u8500_bool_state mute_state, + t_acodec_user user); + +extern t_ab8500_codec_error u8500_acodec_enable_audio_mode(struct + acodec_configuration + *acodec_config); +/*extern t_ab8500_codec_error u8500_acodec_enable_voice_mode(struct acodec_configuration *acodec_config);*/ + +extern t_ab8500_codec_error u8500_acodec_select_input(t_ab8500_codec_src + input_device, + t_acodec_user user, + t_u8500_mode mode); +extern t_ab8500_codec_error u8500_acodec_select_output(t_ab8500_codec_dest + output_device, + t_acodec_user user, + t_u8500_mode mode); + +extern t_ab8500_codec_error u8500_acodec_allocate_ad_slot(t_ab8500_codec_src + input_device, + t_u8500_mode mode); +extern t_ab8500_codec_error u8500_acodec_unallocate_ad_slot(t_ab8500_codec_src + input_device, + t_u8500_mode mode); +extern t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest + output_device, + t_u8500_mode mode); +extern t_ab8500_codec_error u8500_acodec_unallocate_da_slot(t_ab8500_codec_dest + output_device, + t_u8500_mode mode); + +extern t_ab8500_codec_error u8500_acodec_set_src_power_cntrl(t_ab8500_codec_src + input_device, + t_u8500_bool_state + pwr_state); +extern t_ab8500_codec_error +u8500_acodec_set_dest_power_cntrl(t_ab8500_codec_dest output_device, + t_u8500_bool_state pwr_state); + +extern t_u8500_bool_state u8500_acodec_get_src_power_state(t_ab8500_codec_src + input_device); +extern t_u8500_bool_state u8500_acodec_get_dest_power_state(t_ab8500_codec_dest + output_device); +extern t_ab8500_codec_error +u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state); + +extern t_ab8500_codec_error u8500_acodec_unsetuser(t_acodec_user user); +extern t_ab8500_codec_error u8500_acodec_setuser(t_acodec_user user); + +extern void codec_power_init(void); +extern void u8500_acodec_powerdown(void); + +//t_ab8500_codec_error acodec_msp_enable(t_touareg_codec_sample_frequency freq,int channels, t_acodec_user user); + +#define TRG_CODEC_ADDRESS_ON_SPI_BUS (0x0D) + +extern int ab8500_write(u8 block, u32 adr, u8 data); +extern int ab8500_read(u8 block, u32 adr); + +#if 0 +#define FUNC_ENTER() printk("\n -Enter : %s",__FUNCTION__) +#define FUNC_EXIT() printk("\n -Exit : %s",__FUNCTION__) +#else +#define FUNC_ENTER() +#define FUNC_EXIT() +#endif +#endif /*END OF HEADSER FILE */ diff --git a/arch/arm/mach-ux500/include/mach/uart.h b/arch/arm/mach-ux500/include/mach/uart.h new file mode 100644 index 00000000000..1b10a0be5a6 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/uart.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2009 ST-Ericsson SA + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef _U8500_UART_H_ +#define _U8500_UART_H_ + +struct uart_amba_plat_data { + void (*init) (void); + void (*exit) (void); + void (*reset) (void); +}; + +#endif /* _U8500_UART_H_ */ diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h index 0271ca0a83d..9f19d5c8b21 100644 --- a/arch/arm/mach-ux500/include/mach/uncompress.h +++ b/arch/arm/mach-ux500/include/mach/uncompress.h @@ -19,38 +19,46 @@ #define __ASM_ARCH_UNCOMPRESS_H #include <asm/setup.h> +#include <asm/mach-types.h> #include <linux/io.h> +#include <linux/amba/serial.h> #include <mach/hardware.h> -#define U8500_UART_DR 0x80007000 -#define U8500_UART_LCRH 0x8000702c -#define U8500_UART_CR 0x80007030 -#define U8500_UART_FR 0x80007018 +static u32 ux500_uart_base; static void putc(const char c) { /* Do nothing if the UART is not enabled. */ - if (!(__raw_readb(U8500_UART_CR) & 0x1)) + if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) return; if (c == '\n') putc('\r'); - while (__raw_readb(U8500_UART_FR) & (1 << 5)) + while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 5)) barrier(); - __raw_writeb(c, U8500_UART_DR); + __raw_writeb(c, ux500_uart_base + UART01x_DR); } static void flush(void) { - if (!(__raw_readb(U8500_UART_CR) & 0x1)) + if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) return; - while (__raw_readb(U8500_UART_FR) & (1 << 3)) + while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 3)) barrier(); } static inline void arch_decomp_setup(void) { + /* Check in run time if we run on an U8500 or U5500 */ + if (machine_is_u8500() || + machine_is_svp8500v1() || + machine_is_svp8500v2() || + machine_is_snowball() || + machine_is_hrefv60()) { + ux500_uart_base = U8500_UART2_BASE; + } else if (machine_is_u5500()) + ux500_uart_base = U5500_UART0_BASE; } #define arch_decomp_wdog() /* nothing to do here */ diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c index 2288f6a7c51..758e156251b 100644 --- a/arch/arm/mach-ux500/localtimer.c +++ b/arch/arm/mach-ux500/localtimer.c @@ -18,11 +18,20 @@ #include <asm/smp_twd.h> #include <asm/localtimer.h> +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +void smp_timer_broadcast(const struct cpumask *mask); +#endif + /* * Setup the local clock events for a CPU. */ void __cpuinit local_timer_setup(struct clock_event_device *evt) { evt->irq = IRQ_LOCALTIMER; - twd_timer_setup(evt); + +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + evt->broadcast = smp_timer_broadcast; +#endif + + twd_timer_setup_scalable(evt, 2500 * 1000, 2); } diff --git a/arch/arm/mach-ux500/mloader-db8500.c b/arch/arm/mach-ux500/mloader-db8500.c new file mode 100644 index 00000000000..6171a9db82f --- /dev/null +++ b/arch/arm/mach-ux500/mloader-db8500.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 ST-Ericsson + * + * Author: Maxime Coquelin <maxime.coquelin-nonst@stericsson.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ +#include <linux/types.h> +#include <linux/platform_device.h> + +#include <mach/mloader-dbx500.h> + +static struct dbx500_ml_area modem_areas[] = { + { .name = "modem_trace", .start = 0x6000000, .size = 0xf00000 }, + { .name = "modem_shared", .start = 0x6f00000, .size = 0x100000 }, + { .name = "modem_priv", .start = 0x7000000, .size = 0x1000000 }, +}; + +static struct dbx500_ml_fw modem_fws[] = { + { .name = "MODEM", .area = &modem_areas[0], .offset = 0x0 }, + { .name = "IPL", .area = &modem_areas[1], .offset = 0x00 }, +}; + +static struct dbx500_mloader_pdata mloader_fw_data = { + .fws = modem_fws, + .nr_fws = ARRAY_SIZE(modem_fws), + .areas = modem_areas, + .nr_areas = ARRAY_SIZE(modem_areas), +}; + +struct platform_device mloader_fw_device = { + .name = "dbx500_mloader_fw", + .id = -1, + .dev = { + .platform_data = &mloader_fw_data, + }, + .num_resources = 0, +}; + +/* Default areas can be overloaded in cmdline */ +static int __init early_modem_priv(char *p) +{ + struct dbx500_ml_area *area = &modem_areas[2]; + + area->size = memparse(p, &p); + + if (*p == '@') + area->start = memparse(p + 1, &p); + + return 0; +} +early_param("mem_modem", early_modem_priv); + +static int __init early_modem_shared(char *p) +{ + struct dbx500_ml_area *area = &modem_areas[1]; + + area->size = memparse(p, &p); + + if (*p == '@') + area->start = memparse(p + 1, &p); + + return 0; +} +early_param("mem_mshared", early_modem_shared); + +static int __init early_modem_trace(char *p) +{ + struct dbx500_ml_area *area = &modem_areas[0]; + + area->size = memparse(p, &p); + + if (*p == '@') + area->start = memparse(p + 1, &p); + + return 0; +} +early_param("mem_mtrace", early_modem_trace); + diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem_irq.c new file mode 100644 index 00000000000..bfe36b2aa09 --- /dev/null +++ b/arch/arm/mach-ux500/modem_irq.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson. + * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/slab.h> + +#define MODEM_INTCON_BASE_ADDR 0xBFFD3000 +#define MODEM_INTCON_SIZE 0xFFF + +#define DEST_IRQ41_OFFSET 0x2A4 +#define DEST_IRQ43_OFFSET 0x2AC +#define DEST_IRQ45_OFFSET 0x2B4 + +#define PRIO_IRQ41_OFFSET 0x6A4 +#define PRIO_IRQ43_OFFSET 0x6AC +#define PRIO_IRQ45_OFFSET 0x6B4 + +#define ALLOW_IRQ_OFFSET 0x104 + +#define MODEM_INTCON_CPU_NBR 0x1 +#define MODEM_INTCON_PRIO_HIGH 0x0 + +#define MODEM_INTCON_ALLOW_IRQ41 0x0200 +#define MODEM_INTCON_ALLOW_IRQ43 0x0800 +#define MODEM_INTCON_ALLOW_IRQ45 0x2000 + +#define MODEM_IRQ_REG_OFFSET 0x4 + +struct modem_irq { + void __iomem *modem_intcon_base; +}; + + +static void setup_modem_intcon(void __iomem *modem_intcon_base) +{ + /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */ + writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET); + writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET); + writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET); + + /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */ + writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET); + writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET); + writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET); + + /* IC_ALLOW_ARRAY - IRQ enable */ + writel(MODEM_INTCON_ALLOW_IRQ41 | + MODEM_INTCON_ALLOW_IRQ43 | + MODEM_INTCON_ALLOW_IRQ45, + modem_intcon_base + ALLOW_IRQ_OFFSET); +} + +static irqreturn_t modem_cpu_irq_handler(int irq, void *data) +{ + int real_irq; + int virt_irq; + struct modem_irq *mi = (struct modem_irq *)data; + + /* Read modem side IRQ number from modem IRQ controller */ + real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF; + virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq; + + pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X " + "which will be 0x%X (%d) which translates to " + "virtual IRQ 0x%X (%d)!\n", + (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET, + real_irq, + real_irq & 0xFF, + real_irq & 0xFF, + virt_irq, + virt_irq); + + if (virt_irq != 0) + generic_handle_irq(virt_irq); + + pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq); + + return IRQ_HANDLED; +} + +static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip) +{ + set_irq_chip(irq, modem_irq_chip); + set_irq_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + + pr_debug("modem_irq: Created virtual IRQ %d\n", irq); +} + +static int modem_irq_init(void) +{ + int err; + static struct irq_chip modem_irq_chip; + struct modem_irq *mi; + + pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n", + IRQ_DB5500_MODEM); + + mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL); + if (!mi) { + pr_err("modem_irq: Could not allocate device\n"); + return -ENOMEM; + } + + mi->modem_intcon_base = + ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE); + pr_debug("modem_irq: ioremapped modem_intcon_base from " + "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR, + (u32)mi->modem_intcon_base); + + setup_modem_intcon(mi->modem_intcon_base); + + modem_irq_chip = dummy_irq_chip; + modem_irq_chip.name = "modem_irq"; + + /* Create the virtual IRQ:s needed */ + create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip); + create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip); + create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip); + + err = request_threaded_irq(IRQ_DB5500_MODEM, NULL, + modem_cpu_irq_handler, + IRQF_ONESHOT, "ModemIRQ", mi); + if (err) + pr_err("modem_irq: Could not register IRQ %d\n", + IRQ_DB5500_MODEM); + + return 0; +} + +arch_initcall(modem_irq_init); diff --git a/arch/arm/mach-ux500/musb_db8500.c b/arch/arm/mach-ux500/musb_db8500.c new file mode 100644 index 00000000000..c6bc6bf6c05 --- /dev/null +++ b/arch/arm/mach-ux500/musb_db8500.c @@ -0,0 +1,955 @@ +/* + * Copyright (C) 2009 ST Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/usb/musb.h> +#include <linux/interrupt.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/ab8500.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <mach/musb_db8500.h> +#include <mach/prcmu-fw-api.h> + +/* Registers in Bank 0x02 */ +#define AB8500_MAIN_WDOG_CTRL_REG 0x01 + +/* Registers in Bank 0x05 */ +#define AB8500_REGU_VUSB_CTRL_REG 0x82 +#define AB8500_USB_LINE_STAT_REG 0x80 +#define AB8500_USB_LINE_CTRL1_REG 0x81 +#define AB8500_USB_LINE_CTRL2_REG 0x82 +#define AB8500_USB_LINE_CTRL3_REG 0x83 +#define AB8500_USB_LINE_CTRL4_REG 0x84 +#define AB8500_USB_LINE_CTRL5_REG 0x85 +#define AB8500_USB_OTG_CTRL_REG 0x87 +#define AB8500_USB_OTG_STAT_REG 0x88 +#define AB8500_USB_OTG_STAT_REG 0x88 +#define AB8500_USB_CTRL_SPARE_REG 0x89 +#define AB8500_USB_PHY_CTRL_REG 0x8A +#define AB8500_USB_ADP_CTRL_REG 0x93 + +/* Registers in Bank 0x0E */ +#define AB8500_IT_MASK2_REG 0x41 +#define AB8500_IT_MASK12_REG 0x4B +#define AB8500_IT_MASK20_REG 0x53 +#define AB8500_IT_MASK21_REG 0x54 +#define AB8500_IT_SOURCE2_REG 0x01 +#define AB8500_IT_SOURCE20_REG 0x13 + +/* Registers in bank 0x11 */ +#define AB8500_BANK12_ACCESS 0x00 + +/* Registers in bank 0x12 */ +#define AB8500_USB_PHY_TUNE1 0x05 +#define AB8500_USB_PHY_TUNE2 0x06 +#define AB8500_USB_PHY_TUNE3 0x07 + +#define DEVICE_NAME "musb_qos" + +static struct completion usb_link_status_update; +static struct device *device; +static struct regulator *musb_vape_supply; +static struct regulator *musb_vintcore_supply, *musb_smps2_supply; +static struct clk *sysclock; + +static int boot_time_flag = USB_DISABLE; +static int irq_host_remove; +static int irq_device_remove; +static int irq_link_status_update; +static int ab8500_rev; +/* Phy Status. Right now Used for Device only. */ +static int phy_enable_stat = USB_DISABLE; +#ifdef CONFIG_USB_OTG_20 +static int irq_adp_plug; +static int irq_adp_unplug; +#endif +/* + * work queue for USB cable insertion processing + */ +static struct work_struct usb_host_remove; +static struct work_struct usb_device_remove; +static struct work_struct usb_lnk_status_update; +static struct work_struct usb_dedicated_charger_remove; +static struct workqueue_struct *usb_cable_wq; + +static void usb_host_remove_work(struct work_struct *work); +static void usb_device_remove_work(struct work_struct *work); +static void usb_link_status_update_work(struct work_struct *work); +static void usb_dedicated_charger_remove_work(struct work_struct *work); +static void usb_device_phy_en(int enable); +static void usb_kick_watchdog(void); +static void usb_host_phy_en(int enable); + +#include <linux/wakelock.h> +static struct wake_lock ab8500_musb_wakelock; +/** + * stm_musb_states - Different states of musb_chip + * + * Used for USB cable plug-in state machine + */ +enum stm_musb_states { + USB_IDLE, + USB_DEVICE, + USB_HOST, + USB_DEDICATED_CHG, +}; +enum stm_musb_states stm_musb_curr_state = USB_IDLE; + +/* ACA Modification */ +static enum musb_link_status stm_usb_link_curr_state = USB_LINK_NOT_CONFIGURED; +static enum musb_link_status stm_usb_link_prev_state = USB_LINK_NOT_CONFIGURED; + +void musb_set_session(void); +#ifdef CONFIG_PM +void stm_musb_context(int); +#endif + +#ifdef CONFIG_USB_OTG_20 +int musb_adp(void); +static void enable_adp(void) +{ + if (ab8500_rev == AB8500_REV_20) + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_ADP_CTRL_REG, + AB8500_USB_ADP_ENABLE); +} +#endif + +void musb_platform_session_req(void) +{ + /* Discaharge the VBUS */ + /* TODO */ +} + +/* + * musb_platform_device_en(): Enable/Disable the device. + + */ + +void musb_platform_device_en(int enable) +{ + + + if ((enable == 1) && (phy_enable_stat == USB_DISABLE)) { + stm_musb_curr_state = USB_DEVICE; + usb_device_phy_en(USB_ENABLE); + return; + } + + if ((enable == 1) && (phy_enable_stat == USB_ENABLE)) { + /* Phy already enabled. no need to do anything. */ + return; + } + + if ((enable == 0) && (phy_enable_stat == USB_DISABLE)) { + /* Phy already disabled. no need to do anything. */ + return; + } + + if ((enable == 0) && (phy_enable_stat == USB_ENABLE)) { + /* Phy enabled. Disable it */ + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_DISABLE); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + DEVICE_NAME, 50); + prcmu_release_usb_wakeup_state(); + regulator_disable(musb_vape_supply); + regulator_disable(musb_vintcore_supply); + regulator_disable(musb_smps2_supply); + clk_disable(sysclock); + phy_enable_stat = USB_DISABLE; + + return; + } +} + +/** + * usb_kick_watchdog() - Kick the watch dog timer + * + * This function used to Kick the watch dog timer + */ +static void usb_kick_watchdog(void) +{ + if ((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30)) { + abx500_set_register_interruptible(device, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WDOG_CTRL_REG, + AB8500_MAIN_WATCHDOG_ENABLE); + udelay(WATCHDOG_DELAY_US); + abx500_set_register_interruptible(device, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WDOG_CTRL_REG, + (AB8500_MAIN_WATCHDOG_ENABLE + | AB8500_MAIN_WATCHDOG_KICK)); + udelay(WATCHDOG_DELAY_US); + abx500_set_register_interruptible(device, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WDOG_CTRL_REG, + AB8500_MAIN_WATCHDOG_DISABLE); + udelay(WATCHDOG_DELAY_US); + } +} +/** + * usb_host_phy_en() - for enabling the 5V to usb host + * @enable: to enabling the Phy for host. + * + * This function used to set the voltage for USB host mode + */ +static void usb_host_phy_en(int enable) +{ + int volt = 0; + int ret = -1; + + if ((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30)) { + if (enable == USB_ENABLE) { + wake_lock(&ab8500_musb_wakelock); + + clk_enable(sysclock); + regulator_enable(musb_vape_supply); + regulator_enable(musb_smps2_supply); + + /* Set Vintcore12 LDO to 1.3V */ + ret = regulator_set_voltage(musb_vintcore_supply, + 1300000, 1350000); + if (ret < 0) + printk(KERN_ERR "Failed to set the Vintcore" + " to 1.3V, ret=%d\n", ret); + regulator_enable(musb_vintcore_supply); + volt = regulator_get_voltage(musb_vintcore_supply); + if ((volt != 1300000) && (volt != 1350000)) + printk(KERN_ERR "Vintcore is not" + " set to 1.3V" + " volt=%d\n", volt); +#ifdef CONFIG_PM + stm_musb_context(USB_ENABLE); +#endif + usb_kick_watchdog(); + + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + DEVICE_NAME, 100); + + /* Enable the PHY */ + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_HOST_ENABLE); + } else { /* enable == USB_DISABLE */ + if (boot_time_flag) + boot_time_flag = USB_DISABLE; + + /* + * Workaround for bug31952 in ABB cut2.0. Write 0x1 + * before disabling the PHY. + */ + abx500_set_register_interruptible(device, AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_HOST_ENABLE); + + udelay(100); + + abx500_set_register_interruptible(device, AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_HOST_DISABLE); + + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + DEVICE_NAME, 50); + prcmu_release_usb_wakeup_state(); + regulator_disable(musb_vape_supply); + regulator_disable(musb_smps2_supply); + regulator_disable(musb_vintcore_supply); + /* Set Vintcore12 LDO to 0V to 1.35V */ + ret = regulator_set_voltage(musb_vintcore_supply, + 0000000, 1350000); + if (ret < 0) + printk(KERN_ERR "Failed to set the Vintcore" + " to 0V to 1.35V," + " ret=%d\n", ret); + clk_disable(sysclock); + wake_unlock(&ab8500_musb_wakelock); + } + } +} + +/** + * usb_host_remove_handler() - Removed the USB host cable + * + * This function used to detect the USB host cable removed. + */ +static irqreturn_t usb_host_remove_handler(int irq, void *data) +{ + if (stm_musb_curr_state == USB_HOST) { + /* Change the current state */ + stm_musb_curr_state = USB_IDLE; + queue_work(usb_cable_wq, &usb_host_remove); + return IRQ_HANDLED; + } + return IRQ_NONE; +} +/** + * usb_device_phy_en() - for enabling the 5V to usb gadget + * @enable: to enabling the Phy for device. + * + * This function used to set the voltage for USB gadget mode. + */ +static void usb_device_phy_en(int enable) +{ + int volt = 0; + int ret = -1; + + if (phy_enable_stat == enable) + return; + + if ((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30)) { + if (enable == USB_ENABLE) { + wake_lock(&ab8500_musb_wakelock); + clk_enable(sysclock); + phy_enable_stat = USB_ENABLE; + regulator_enable(musb_vape_supply); + regulator_enable(musb_smps2_supply); + + /* Set Vintcore12 LDO to 1.3V */ + ret = regulator_set_voltage(musb_vintcore_supply, + 1300000, 1350000); + if (ret < 0) + printk(KERN_ERR "Failed to set the Vintcore" + " to 1.3V, ret=%d\n", ret); + regulator_enable(musb_vintcore_supply); + volt = regulator_get_voltage(musb_vintcore_supply); + if ((volt != 1300000) && (volt != 1350000)) + printk(KERN_ERR "Vintcore is not" + " set to 1.3V" + " volt=%d\n", volt); +#ifdef CONFIG_PM + stm_musb_context(USB_ENABLE); +#endif + usb_kick_watchdog(); + + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + DEVICE_NAME, 100); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_ENABLE); + } else { /* enable == USB_DISABLE */ + if (boot_time_flag) + boot_time_flag = USB_DISABLE; + + /* + * Workaround for bug31952 in ABB cut2.0. Write 0x1 + * before disabling the PHY. + */ + abx500_set_register_interruptible(device, AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_ENABLE); + + udelay(100); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_DISABLE); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, + DEVICE_NAME, 50); + prcmu_release_usb_wakeup_state(); + phy_enable_stat = USB_DISABLE; + regulator_disable(musb_vape_supply); + regulator_disable(musb_smps2_supply); + regulator_disable(musb_vintcore_supply); + /* Set Vintcore12 LDO to 0V to 1.35V */ + ret = regulator_set_voltage(musb_vintcore_supply, + 0000000, 1350000); + if (ret < 0) + printk(KERN_ERR "Failed to set the Vintcore" + " to 0V to 1.35V," + " ret=%d\n", ret); + clk_disable(sysclock); + stm_musb_context(USB_DISABLE); + wake_unlock(&ab8500_musb_wakelock); + } + } +} + +/** + * usb_device_remove_handler() - remove the 5V to usb device + * + * This function used to remove the voltage for USB device mode. + */ +static irqreturn_t usb_device_remove_handler(int irq, void *data) +{ + if (stm_musb_curr_state == USB_DEVICE) { + /* Change the current state */ + stm_musb_curr_state = USB_IDLE; + queue_work(usb_cable_wq, &usb_device_remove); + return IRQ_HANDLED; + } else if (stm_musb_curr_state == USB_DEDICATED_CHG) { + stm_musb_curr_state = USB_IDLE; + if (ab8500_rev == AB8500_REV_20) + queue_work(usb_cable_wq, &usb_dedicated_charger_remove); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/** + * usb_link_status_update_handler() - USB Link status update complete + * + * This function is used to signal the completion of + * USB Link status register update + */ +static irqreturn_t usb_link_status_update_handler(int irq, void *data) +{ + queue_work(usb_cable_wq, &usb_lnk_status_update); + return IRQ_HANDLED; +} + +#ifdef CONFIG_USB_OTG_20 +static irqreturn_t irq_adp_plug_handler(int irq, void *data) +{ + int ret; + + ret = musb_adp(); + if (ret) { + + if (stm_musb_curr_state == USB_HOST) + musb_set_session(); + if (stm_musb_curr_state == USB_DEVICE) { + /*TODO*/ + /* Generate SRP */ + } + if (stm_musb_curr_state == USB_IDLE) + printk(KERN_INFO "No device is connected\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t irq_adp_unplug_handler(int irq, void *data) +{ + if (stm_musb_curr_state == USB_HOST) { + stm_musb_curr_state = USB_IDLE; + queue_work(usb_cable_wq, &usb_host_remove); + } + if (stm_musb_curr_state == USB_DEVICE) { + stm_musb_curr_state = USB_IDLE; + queue_work(usb_cable_wq, &usb_device_remove); + } + + return IRQ_HANDLED; +} +#endif + +/** + * musb_phy_en : register USB callback handlers for ab8500 + * @mode: value for mode. + * + * This function is used to register USB callback handlers for ab8500. + */ +int musb_phy_en(u8 mode) +{ + int ret = -1; + + if (!device) + return -EINVAL; + ab8500_rev = abx500_get_chip_id(device); + if (ab8500_rev < 0) { + dev_err(device, "get chip id failed\n"); + return ab8500_rev; + } + if (!((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30))) { + dev_err(device, "Unknown AB type!\n"); + return -ENODEV; + } + musb_vape_supply = regulator_get(device, "v-ape"); + if (IS_ERR(musb_vape_supply)) { + dev_err(device, "Could not get %s:v-ape supply\n", + dev_name(device)); + + ret = PTR_ERR(musb_vape_supply); + return ret; + } + musb_vintcore_supply = regulator_get(device, "v-intcore"); + if (IS_ERR(musb_vintcore_supply)) { + dev_err(device, "Could not get %s:v-intcore12 supply\n", + dev_name(device)); + + ret = PTR_ERR(musb_vintcore_supply); + return ret; + } + musb_smps2_supply = regulator_get(device, "musb_1v8"); + if (IS_ERR(musb_smps2_supply)) { + dev_err(device, "Could not get %s:v-intcore12 supply\n", + dev_name(device)); + + ret = PTR_ERR(musb_smps2_supply); + return ret; + } + sysclock = clk_get(device, "sysclk"); + if (IS_ERR(sysclock)) { + ret = PTR_ERR(sysclock); + sysclock = NULL; + return ret; + } + /* + * When usb cable is not connected,set Qos for VAPE to 50. + * This is done to run APE at low OPP when usb is not used. + */ + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, DEVICE_NAME, 50); + if ((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30)) { + if (mode == MUSB_HOST || mode == MUSB_OTG) { + ret = request_threaded_irq(irq_host_remove, NULL, + usb_host_remove_handler, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-host-remove", device); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb host" + " removal\n"); + return ret; + } + } + if ((mode == MUSB_PERIPHERAL) || (mode == MUSB_OTG)) { + ret = request_threaded_irq(irq_device_remove, NULL, + usb_device_remove_handler, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-device-remove", device); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb host" + " removal\n"); + return ret; + } + } + + /* create a thread for work */ + usb_cable_wq = create_singlethread_workqueue( + "usb_cable_wq"); + if (usb_cable_wq == NULL) + return -ENOMEM; + + INIT_WORK(&usb_host_remove, usb_host_remove_work); + INIT_WORK(&usb_device_remove, usb_device_remove_work); + INIT_WORK(&usb_lnk_status_update, + usb_link_status_update_work); + + if (ab8500_rev == AB8500_REV_20) + INIT_WORK(&usb_dedicated_charger_remove, + usb_dedicated_charger_remove_work); + + /* Required for Host, Device and OTG mode */ + init_completion(&usb_link_status_update); + ret = request_threaded_irq(irq_link_status_update, + NULL, usb_link_status_update_handler, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-link-status-update", device); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb charge" + " detect done\n"); + return ret; + } +#ifdef CONFIG_USB_OTG_20 + ret = request_threaded_irq(irq_adp_plug, NULL, + irq_adp_plug_handler, + IRQF_SHARED, "usb-adp-plug", device); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb adp" + " plug\n"); + return ret; + } + ret = request_threaded_irq(irq_adp_unplug, NULL, + irq_adp_unplug_handler, + IRQF_SHARED, "usb-adp-unplug", device); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb adp" + " unplug\n"); + return ret; + } +#endif + /* Write Phy tuning values */ + if (ab8500_rev == AB8500_REV_30) { + /* Enable the PBT/Bank 0x12 access */ + ret = abx500_set_register_interruptible(device, + AB8500_DEVELOPMENT, + AB8500_BANK12_ACCESS, + 0x01); + if (ret < 0) + printk(KERN_ERR "Failed to enable bank12" + " access ret=%d\n", ret); + + ret = abx500_set_register_interruptible(device, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE1, + 0xC8); + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE1" + " register ret=%d\n", ret); + + ret = abx500_set_register_interruptible(device, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE2, + 0x00); + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE2" + " register ret=%d\n", ret); + + ret = abx500_set_register_interruptible(device, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE3, + 0x78); + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE3" + " regester ret=%d\n", ret); + + /* Switch to normal mode/disable Bank 0x12 access */ + ret = abx500_set_register_interruptible(device, + AB8500_DEVELOPMENT, + AB8500_BANK12_ACCESS, + 0x00); + if (ret < 0) + printk(KERN_ERR "Failed to switch bank12" + " access ret=%d\n", ret); + } + usb_kick_watchdog(); + } + return 0; +} +/** + * musb_force_detect : detect the USB cable during boot time. + * @mode: value for mode. + * + * This function is used to detect the USB cable during boot time. + */ +int musb_force_detect(u8 mode) +{ + int ret; + u8 usb_status = 0; + u8 val = 0; + + if (!device) + return -EINVAL; + + if ((ab8500_rev == AB8500_REV_20) + || (ab8500_rev == AB8500_REV_30)) { + /* Disabling PHY before selective enable or disable */ + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_ENABLE); + + udelay(100); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_DISABLE); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_HOST_ENABLE); + + udelay(100); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_HOST_DISABLE); + + if (mode == MUSB_HOST || mode == MUSB_OTG) { + ret = abx500_get_register_interruptible(device, + AB8500_INTERRUPT, AB8500_IT_SOURCE20_REG, + &usb_status); + if (ret < 0) { + dev_err(device, "Read IT 20 failed\n"); + return ret; + } + + if (usb_status & AB8500_SRC_INT_USB_HOST) { + boot_time_flag = USB_ENABLE; + /* Change the current state */ + stm_musb_curr_state = USB_HOST; + usb_host_phy_en(USB_ENABLE); + } + } + if (mode == MUSB_PERIPHERAL || mode == MUSB_OTG) { + ret = abx500_get_register_interruptible(device, + AB8500_INTERRUPT, AB8500_IT_SOURCE2_REG, + &usb_status); + if (ret < 0) { + dev_err(device, "Read IT 2 failed\n"); + return ret; + } + + if (usb_status & AB8500_SRC_INT_USB_DEVICE) { + /* Check if it is a dedicated charger */ + (void)abx500_get_register_interruptible(device, + AB8500_USB, AB8500_USB_LINE_STAT_REG, &val); + + val = (val & AB8500_USB_LINK_STATUS) >> 3; + + if (val == USB_LINK_DEDICATED_CHG) { + /* Change the current state */ + stm_musb_curr_state = USB_DEDICATED_CHG; + } else { + boot_time_flag = USB_ENABLE; + /* Change the current state */ + stm_musb_curr_state = USB_DEVICE; + usb_device_phy_en(USB_ENABLE); + } + } + } + } + return 0; +} + +/** + * usb_host_remove_work : work handler for host cable insert. + * @work: work structure + * + * This function is used to handle the host cable insert work. + */ +static void usb_host_remove_work(struct work_struct *work) +{ + usb_host_phy_en(USB_DISABLE); +} + +/** + * usb_device_remove_work : work handler for device cable insert. + * @work: work structure + * + * This function is used to handle the device cable insert work. + */ +static void usb_device_remove_work(struct work_struct *work) +{ + usb_device_phy_en(USB_DISABLE); +} + +/* Work created for PHY handling in case of dedicated charger disconnect */ +static void usb_dedicated_charger_remove_work(struct work_struct *work) +{ + /* + * Workaround for bug31952 in ABB cut2.0. Write 0x1 + * before disabling the PHY. + */ + abx500_set_register_interruptible(device, AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_ENABLE); + + udelay(100); + + abx500_set_register_interruptible(device, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_USB_DEVICE_DISABLE); +} + +/* Work created after an link status update handler*/ +static void usb_link_status_update_work(struct work_struct *work) +{ + u8 val = 0; + + (void)abx500_get_register_interruptible(device, + AB8500_USB, AB8500_USB_LINE_STAT_REG, &val); + + val = (val & AB8500_USB_LINK_STATUS) >> 3; + stm_usb_link_curr_state = (enum stm_musb_states) val; + + switch (stm_usb_link_curr_state) { + case USB_LINK_DEDICATED_CHG: + stm_musb_curr_state = USB_DEDICATED_CHG; + break; + case USB_LINK_NOT_CONFIGURED: + case USB_LINK_NOT_VALID_LINK: + case USB_LINK_ACA_RID_B: + /* PHY is disabled */ + switch (stm_musb_curr_state) { + case USB_DEVICE: + /* Change the current state */ + stm_musb_curr_state = USB_IDLE; + usb_device_phy_en(USB_DISABLE); + break; + case USB_HOST: + /* Change the current state */ + stm_musb_curr_state = USB_IDLE; + usb_host_phy_en(USB_DISABLE); + break; + case USB_IDLE: + case USB_DEDICATED_CHG: + break; + } + break; + case USB_LINK_STD_HOST_NC: + case USB_LINK_STD_HOST_C_NS: + case USB_LINK_STD_HOST_C_S: + case USB_LINK_HOST_CHG_NM: + case USB_LINK_HOST_CHG_HS: + case USB_LINK_HOST_CHG_HS_CHIRP: + case USB_LINK_ACA_RID_C_NM: + case USB_LINK_ACA_RID_C_HS: + case USB_LINK_ACA_RID_C_HS_CHIRP: + /* Device PHY is enabled */ + switch (stm_musb_curr_state) { + case USB_HOST: + /* Change the current state */ + stm_musb_curr_state = USB_DEVICE; + usb_host_phy_en(USB_DISABLE); + usb_device_phy_en(USB_ENABLE); + break; + case USB_IDLE: + /* Change the current state */ + stm_musb_curr_state = USB_DEVICE; + usb_device_phy_en(USB_ENABLE); + break; + case USB_DEVICE: + case USB_DEDICATED_CHG: + break; + } + break; + case USB_LINK_HM_IDGND: + case USB_LINK_ACA_RID_A: + /* Host PHY is enabled */ + switch (stm_musb_curr_state) { + case USB_DEVICE: + /* Change the current state */ + stm_musb_curr_state = USB_HOST; + usb_device_phy_en(USB_DISABLE); + usb_host_phy_en(USB_ENABLE); + musb_set_session(); + break; + case USB_IDLE: + /* Change the current state */ + stm_musb_curr_state = USB_HOST; + usb_host_phy_en(USB_ENABLE); + musb_set_session(); + break; + case USB_HOST: + case USB_DEDICATED_CHG: + break; + } + break; + case USB_LINK_OTG_HOST_NO_CURRENT: + default: + break; + } + stm_usb_link_prev_state = stm_usb_link_curr_state; +} + +/* + * musb_get_abx500_rev : Get the ABx500 revision number + * + * This function returns the ABx500 revision number. + */ +int musb_get_abx500_rev() +{ + return ab8500_rev; +} + +static int __devinit ab8500_musb_probe(struct platform_device *pdev) +{ +#ifdef CONFIG_USB_OTG_20 + u8 usb_status = 0; + int ret; +#endif + device = &pdev->dev; + irq_host_remove = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); + if (irq_host_remove < 0) { + dev_err(&pdev->dev, "Host remove irq not found, err %d\n", + irq_host_remove); + return irq_host_remove; + } + + irq_device_remove = platform_get_irq_byname(pdev, "VBUS_DET_F"); + if (irq_device_remove < 0) { + dev_err(&pdev->dev, "Device remove irq not found, err %d\n", + irq_device_remove); + return irq_device_remove; + } + + irq_link_status_update = platform_get_irq_byname(pdev, + "USB_LINK_STATUS"); + if (irq_link_status_update < 0) { + dev_err(&pdev->dev, "USB Link status irq not found, err %d\n", + irq_link_status_update); + return irq_link_status_update; + } + +#ifdef CONFIG_USB_OTG_20 + enable_adp(); + irq_adp_plug = platform_get_irq_byname(pdev, "USB_ADP_PROBE_PLUG"); + if (irq_adp_plug < 0) { + dev_err(&pdev->dev, "ADP Probe plug irq not found, err %d\n", + irq_adp_plug); + return irq_adp_plug; + } + irq_adp_unplug = platform_get_irq_byname(pdev, "USB_ADP_PROBE_UNPLUG"); + if (irq_adp_unplug < 0) { + dev_err(&pdev->dev, "ADP Probe unplug irq not found," + " err %d\n", + irq_adp_unplug); + return irq_adp_unplug; + } + ret = abx500_get_register_interruptible(device, + AB8500_INTERRUPT, AB8500_IT_SOURCE20_REG, + &usb_status); + if (ret < 0) { + dev_err(device, "Read IT 2 failed\n"); + return ret; + } + + if (usb_status & AB8500_USB_DEVICE_ENABLE) { + boot_time_flag = USB_ENABLE; + stm_musb_curr_state = USB_DEVICE; + musb_phy_en(MUSB_HOST); + } +#endif + + wake_lock_init(&ab8500_musb_wakelock, WAKE_LOCK_SUSPEND, "ab8500-usb"); + return 0; +} + +static int __devexit ab8500_musb_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ab8500_musb_driver = { + .driver = { + .name = "ab8500-usb", + .owner = THIS_MODULE, + }, + .probe = ab8500_musb_probe, + .remove = __devexit_p(ab8500_musb_remove), +}; + +static int __init ab8500_musb_init(void) +{ + return platform_driver_register(&ab8500_musb_driver); +} +module_init(ab8500_musb_init); + +static void __exit ab8500_musb_exit(void) +{ + platform_driver_unregister(&ab8500_musb_driver); +} +module_exit(ab8500_musb_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h new file mode 100644 index 00000000000..bf50c21fe69 --- /dev/null +++ b/arch/arm/mach-ux500/pins-db5500.h @@ -0,0 +1,620 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License, version 2 + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + */ + +#ifndef __MACH_DB5500_PINS_H +#define __MACH_DB5500_PINS_H + +#define GPIO0_GPIO PIN_CFG(0, GPIO) +#define GPIO0_SM_CS3n PIN_CFG(0, ALT_A) + +#define GPIO1_GPIO PIN_CFG(1, GPIO) +#define GPIO1_SM_A3 PIN_CFG(1, ALT_A) + +#define GPIO2_GPIO PIN_CFG(2, GPIO) +#define GPIO2_SM_A4 PIN_CFG(2, ALT_A) +#define GPIO2_SM_AVD PIN_CFG(2, ALT_B) + +#define GPIO3_GPIO PIN_CFG(3, GPIO) +#define GPIO3_I2C1_SCL PIN_CFG(3, ALT_A) + +#define GPIO4_GPIO PIN_CFG(4, GPIO) +#define GPIO4_I2C1_SDA PIN_CFG(4, ALT_A) + +#define GPIO5_GPIO PIN_CFG(5, GPIO) +#define GPIO5_MC0_DAT0 PIN_CFG(5, ALT_A) +#define GPIO5_SM_ADQ8 PIN_CFG(5, ALT_B) + +#define GPIO6_GPIO PIN_CFG(6, GPIO) +#define GPIO6_MC0_DAT1 PIN_CFG(6, ALT_A) +#define GPIO6_SM_ADQ0 PIN_CFG(6, ALT_B) + +#define GPIO7_GPIO PIN_CFG(7, GPIO) +#define GPIO7_MC0_DAT2 PIN_CFG(7, ALT_A) +#define GPIO7_SM_ADQ9 PIN_CFG(7, ALT_B) + +#define GPIO8_GPIO PIN_CFG(8, GPIO) +#define GPIO8_MC0_DAT3 PIN_CFG(8, ALT_A) +#define GPIO8_SM_ADQ1 PIN_CFG(8, ALT_B) + +#define GPIO9_GPIO PIN_CFG(9, GPIO) +#define GPIO9_MC0_DAT4 PIN_CFG(9, ALT_A) +#define GPIO9_SM_ADQ10 PIN_CFG(9, ALT_B) + +#define GPIO10_GPIO PIN_CFG(10, GPIO) +#define GPIO10_MC0_DAT5 PIN_CFG(10, ALT_A) +#define GPIO10_SM_ADQ2 PIN_CFG(10, ALT_B) + +#define GPIO11_GPIO PIN_CFG(11, GPIO) +#define GPIO11_MC0_DAT6 PIN_CFG(11, ALT_A) +#define GPIO11_SM_ADQ11 PIN_CFG(11, ALT_B) + +#define GPIO12_GPIO PIN_CFG(12, GPIO) +#define GPIO12_MC0_DAT7 PIN_CFG(12, ALT_A) +#define GPIO12_SM_ADQ3 PIN_CFG(12, ALT_B) + +#define GPIO13_GPIO PIN_CFG(13, GPIO) +#define GPIO13_MC0_CMD PIN_CFG(13, ALT_A) +#define GPIO13_SM_BUSY0n PIN_CFG(13, ALT_B) +#define GPIO13_SM_WAIT0n PIN_CFG(13, ALT_C) + +#define GPIO14_GPIO PIN_CFG(14, GPIO) +#define GPIO14_MC0_CLK PIN_CFG(14, ALT_A) +#define GPIO14_SM_CS1n PIN_CFG(14, ALT_B) +#define GPIO14_SM_CKO PIN_CFG(14, ALT_C) + +#define GPIO15_GPIO PIN_CFG(15, GPIO) +#define GPIO15_SM_A5 PIN_CFG(15, ALT_A) +#define GPIO15_SM_CLE PIN_CFG(15, ALT_B) + +#define GPIO16_GPIO PIN_CFG(16, GPIO) +#define GPIO16_MC2_CMD PIN_CFG(16, ALT_A) +#define GPIO16_SM_OEn PIN_CFG(16, ALT_B) + +#define GPIO17_GPIO PIN_CFG(17, GPIO) +#define GPIO17_MC2_CLK PIN_CFG(17, ALT_A) +#define GPIO17_SM_WEn PIN_CFG(17, ALT_B) + +#define GPIO18_GPIO PIN_CFG(18, GPIO) +#define GPIO18_SM_A6 PIN_CFG(18, ALT_A) +#define GPIO18_SM_ALE PIN_CFG(18, ALT_B) +#define GPIO18_SM_AVDn PIN_CFG(18, ALT_C) + +#define GPIO19_GPIO PIN_CFG(19, GPIO) +#define GPIO19_MC2_DAT1 PIN_CFG(19, ALT_A) +#define GPIO19_SM_ADQ4 PIN_CFG(19, ALT_B) + +#define GPIO20_GPIO PIN_CFG(20, GPIO) +#define GPIO20_MC2_DAT3 PIN_CFG(20, ALT_A) +#define GPIO20_SM_ADQ5 PIN_CFG(20, ALT_B) + +#define GPIO21_GPIO PIN_CFG(21, GPIO) +#define GPIO21_MC2_DAT5 PIN_CFG(21, ALT_A) +#define GPIO21_SM_ADQ6 PIN_CFG(21, ALT_B) + +#define GPIO22_GPIO PIN_CFG(22, GPIO) +#define GPIO22_MC2_DAT7 PIN_CFG(22, ALT_A) +#define GPIO22_SM_ADQ7 PIN_CFG(22, ALT_B) + +#define GPIO23_GPIO PIN_CFG(23, GPIO) +#define GPIO23_MC2_DAT0 PIN_CFG(23, ALT_A) +#define GPIO23_SM_ADQ12 PIN_CFG(23, ALT_B) +#define GPIO23_MC0_DAT1 PIN_CFG(23, ALT_C) + +#define GPIO24_GPIO PIN_CFG(24, GPIO) +#define GPIO24_MC2_DAT2 PIN_CFG(24, ALT_A) +#define GPIO24_SM_ADQ13 PIN_CFG(24, ALT_B) +#define GPIO24_MC0_DAT3 PIN_CFG(24, ALT_C) + +#define GPIO25_GPIO PIN_CFG(25, GPIO) +#define GPIO25_MC2_DAT4 PIN_CFG(25, ALT_A) +#define GPIO25_SM_ADQ14 PIN_CFG(25, ALT_B) +#define GPIO25_MC0_CMD PIN_CFG(25, ALT_C) + +#define GPIO26_GPIO PIN_CFG(26, GPIO) +#define GPIO26_MC2_DAT6 PIN_CFG(26, ALT_A) +#define GPIO26_SM_ADQ15 PIN_CFG(26, ALT_B) + +#define GPIO27_GPIO PIN_CFG(27, GPIO) +#define GPIO27_SM_CS0n PIN_CFG(27, ALT_A) +#define GPIO27_SM_PS0n PIN_CFG(27, ALT_B) + +#define GPIO28_GPIO PIN_CFG(28, GPIO) +#define GPIO28_U0_TXD PIN_CFG(28, ALT_A) +#define GPIO28_SM_A0 PIN_CFG(28, ALT_B) + +#define GPIO29_GPIO PIN_CFG(29, GPIO) +#define GPIO29_U0_RXD PIN_CFG(29, ALT_A) +#define GPIO29_SM_A1 PIN_CFG(29, ALT_B) +#define GPIO29_PWM_0 PIN_CFG(29, ALT_C) + +#define GPIO30_GPIO PIN_CFG(30, GPIO) +#define GPIO30_MC0_DAT5 PIN_CFG(30, ALT_A) +#define GPIO30_SM_A2 PIN_CFG(30, ALT_B) +#define GPIO30_PWM_1 PIN_CFG(30, ALT_C) + +#define GPIO31_GPIO PIN_CFG(31, GPIO) +#define GPIO31_MC0_DAT7 PIN_CFG(31, ALT_A) +#define GPIO31_SM_CS2n PIN_CFG(31, ALT_B) +#define GPIO31_PWM_2 PIN_CFG(31, ALT_C) + +#define GPIO32_GPIO PIN_CFG(32, GPIO) +#define GPIO32_MSP0_TCK PIN_CFG(32, ALT_A) +#define GPIO32_ACCI2S0_SCK PIN_CFG(32, ALT_B) + +#define GPIO33_GPIO PIN_CFG(33, GPIO) +#define GPIO33_MSP0_TFS PIN_CFG(33, ALT_A) +#define GPIO33_ACCI2S0_WS PIN_CFG(33, ALT_B) + +#define GPIO34_GPIO PIN_CFG(34, GPIO) +#define GPIO34_MSP0_TXD PIN_CFG(34, ALT_A) +#define GPIO34_ACCI2S0_DLD PIN_CFG(34, ALT_B) + +#define GPIO35_GPIO PIN_CFG(35, GPIO) +#define GPIO35_MSP0_RXD PIN_CFG(35, ALT_A) +#define GPIO35_ACCI2S0_ULD PIN_CFG(35, ALT_B) + +#define GPIO64_GPIO PIN_CFG(64, GPIO) +#define GPIO64_USB_DAT0 PIN_CFG(64, ALT_A) +#define GPIO64_U0_TXD PIN_CFG(64, ALT_B) + +#define GPIO65_GPIO PIN_CFG(65, GPIO) +#define GPIO65_USB_DAT1 PIN_CFG(65, ALT_A) +#define GPIO65_U0_RXD PIN_CFG(65, ALT_B) + +#define GPIO66_GPIO PIN_CFG(66, GPIO) +#define GPIO66_USB_DAT2 PIN_CFG(66, ALT_A) + +#define GPIO67_GPIO PIN_CFG(67, GPIO) +#define GPIO67_USB_DAT3 PIN_CFG(67, ALT_A) + +#define GPIO68_GPIO PIN_CFG(68, GPIO) +#define GPIO68_USB_DAT4 PIN_CFG(68, ALT_A) + +#define GPIO69_GPIO PIN_CFG(69, GPIO) +#define GPIO69_USB_DAT5 PIN_CFG(69, ALT_A) + +#define GPIO70_GPIO PIN_CFG(70, GPIO) +#define GPIO70_USB_DAT6 PIN_CFG(70, ALT_A) + +#define GPIO71_GPIO PIN_CFG(71, GPIO) +#define GPIO71_USB_DAT7 PIN_CFG(71, ALT_A) + +#define GPIO72_GPIO PIN_CFG(72, GPIO) +#define GPIO72_USB_STP PIN_CFG(72, ALT_A) + +#define GPIO73_GPIO PIN_CFG(73, GPIO) +#define GPIO73_USB_DIR PIN_CFG(73, ALT_A) + +#define GPIO74_GPIO PIN_CFG(74, GPIO) +#define GPIO74_USB_NXT PIN_CFG(74, ALT_A) + +#define GPIO75_GPIO PIN_CFG(75, GPIO) +#define GPIO75_USB_XCLK PIN_CFG(75, ALT_A) + +#define GPIO76_GPIO PIN_CFG(76, GPIO) + +#define GPIO77_GPIO PIN_CFG(77, GPIO) +#define GPIO77_ACCTX_ON PIN_CFG(77, ALT_A) + +#define GPIO78_GPIO PIN_CFG(78, GPIO) +#define GPIO78_IRQn PIN_CFG(78, ALT_A) + +#define GPIO79_GPIO PIN_CFG(79, GPIO) +#define GPIO79_ACCSIM_Clk PIN_CFG(79, ALT_A) + +#define GPIO80_GPIO PIN_CFG(80, GPIO) +#define GPIO80_ACCSIM_Da PIN_CFG(80, ALT_A) + +#define GPIO81_GPIO PIN_CFG(81, GPIO) +#define GPIO81_ACCSIM_Reset PIN_CFG(81, ALT_A) + +#define GPIO82_GPIO PIN_CFG(82, GPIO) +#define GPIO82_ACCSIM_DDir PIN_CFG(82, ALT_A) + +#define GPIO96_GPIO PIN_CFG(96, GPIO) +#define GPIO96_MSP1_TCK PIN_CFG(96, ALT_A) +#define GPIO96_PRCMU_DEBUG3 PIN_CFG(96, ALT_B) +#define GPIO96_PRCMU_DEBUG7 PIN_CFG(96, ALT_C) + +#define GPIO97_GPIO PIN_CFG(97, GPIO) +#define GPIO97_MSP1_TFS PIN_CFG(97, ALT_A) +#define GPIO97_PRCMU_DEBUG2 PIN_CFG(97, ALT_B) +#define GPIO97_PRCMU_DEBUG6 PIN_CFG(97, ALT_C) + +#define GPIO98_GPIO PIN_CFG(98, GPIO) +#define GPIO98_MSP1_TXD PIN_CFG(98, ALT_A) +#define GPIO98_PRCMU_DEBUG1 PIN_CFG(98, ALT_B) +#define GPIO98_PRCMU_DEBUG5 PIN_CFG(98, ALT_C) + +#define GPIO99_GPIO PIN_CFG(99, GPIO) +#define GPIO99_MSP1_RXD PIN_CFG(99, ALT_A) +#define GPIO99_PRCMU_DEBUG0 PIN_CFG(99, ALT_B) +#define GPIO99_PRCMU_DEBUG4 PIN_CFG(99, ALT_C) + +#define GPIO100_GPIO PIN_CFG(100, GPIO) +#define GPIO100_I2C0_SCL PIN_CFG(100, ALT_A) + +#define GPIO101_GPIO PIN_CFG(101, GPIO) +#define GPIO101_I2C0_SDA PIN_CFG(101, ALT_A) + +#define GPIO128_GPIO PIN_CFG(128, GPIO) +#define GPIO128_KP_I0 PIN_CFG(128, ALT_A) +#define GPIO128_BUSMON_D0 PIN_CFG(128, ALT_B) + +#define GPIO129_GPIO PIN_CFG(129, GPIO) +#define GPIO129_KP_O0 PIN_CFG(129, ALT_A) +#define GPIO129_BUSMON_D1 PIN_CFG(129, ALT_B) + +#define GPIO130_GPIO PIN_CFG(130, GPIO) +#define GPIO130_KP_I1 PIN_CFG(130, ALT_A) +#define GPIO130_BUSMON_D2 PIN_CFG(130, ALT_B) + +#define GPIO131_GPIO PIN_CFG(131, GPIO) +#define GPIO131_KP_O1 PIN_CFG(131, ALT_A) +#define GPIO131_BUSMON_D3 PIN_CFG(131, ALT_B) + +#define GPIO132_GPIO PIN_CFG(132, GPIO) +#define GPIO132_KP_I2 PIN_CFG(132, ALT_A) +#define GPIO132_ETM_D15 PIN_CFG(132, ALT_B) +#define GPIO132_STMAPE_CLK PIN_CFG(132, ALT_C) + +#define GPIO133_GPIO PIN_CFG(133, GPIO) +#define GPIO133_KP_O2 PIN_CFG(133, ALT_A) +#define GPIO133_ETM_D14 PIN_CFG(133, ALT_B) +#define GPIO133_U0_RXD PIN_CFG(133, ALT_C) + +#define GPIO134_GPIO PIN_CFG(134, GPIO) +#define GPIO134_KP_I3 PIN_CFG(134, ALT_A) +#define GPIO134_ETM_D13 PIN_CFG(134, ALT_B) +#define GPIO134_STMAPE_DAT0 PIN_CFG(134, ALT_C) + +#define GPIO135_GPIO PIN_CFG(135, GPIO) +#define GPIO135_KP_O3 PIN_CFG(135, ALT_A) +#define GPIO135_ETM_D12 PIN_CFG(135, ALT_B) +#define GPIO135_STMAPE_DAT1 PIN_CFG(135, ALT_C) + +#define GPIO136_GPIO PIN_CFG(136, GPIO) +#define GPIO136_KP_I4 PIN_CFG(136, ALT_A) +#define GPIO136_ETM_D11 PIN_CFG(136, ALT_B) +#define GPIO136_STMAPE_DAT2 PIN_CFG(136, ALT_C) + +#define GPIO137_GPIO PIN_CFG(137, GPIO) +#define GPIO137_KP_O4 PIN_CFG(137, ALT_A) +#define GPIO137_ETM_D10 PIN_CFG(137, ALT_B) +#define GPIO137_STMAPE_DAT3 PIN_CFG(137, ALT_C) + +#define GPIO138_GPIO PIN_CFG(138, GPIO) +#define GPIO138_KP_I5 PIN_CFG(138, ALT_A) +#define GPIO138_ETM_D9 PIN_CFG(138, ALT_B) +#define GPIO138_U0_TXD PIN_CFG(138, ALT_C) + +#define GPIO139_GPIO PIN_CFG(139, GPIO) +#define GPIO139_KP_O5 PIN_CFG(139, ALT_A) +#define GPIO139_ETM_D8 PIN_CFG(139, ALT_B) +#define GPIO139_BUSMON_D11 PIN_CFG(139, ALT_C) + +#define GPIO140_GPIO PIN_CFG(140, GPIO) +#define GPIO140_KP_I6 PIN_CFG(140, ALT_A) +#define GPIO140_ETM_D7 PIN_CFG(140, ALT_B) +#define GPIO140_STMAPE_CLK PIN_CFG(140, ALT_C) + +#define GPIO141_GPIO PIN_CFG(141, GPIO) +#define GPIO141_KP_O6 PIN_CFG(141, ALT_A) +#define GPIO141_ETM_D6 PIN_CFG(141, ALT_B) +#define GPIO141_U0_RXD PIN_CFG(141, ALT_C) + +#define GPIO142_GPIO PIN_CFG(142, GPIO) +#define GPIO142_KP_I7 PIN_CFG(142, ALT_A) +#define GPIO142_ETM_D5 PIN_CFG(142, ALT_B) +#define GPIO142_STMAPE_DAT0 PIN_CFG(142, ALT_C) + +#define GPIO143_GPIO PIN_CFG(143, GPIO) +#define GPIO143_KP_O7 PIN_CFG(143, ALT_A) +#define GPIO143_ETM_D4 PIN_CFG(143, ALT_B) +#define GPIO143_STMAPE_DAT1 PIN_CFG(143, ALT_C) + +#define GPIO144_GPIO PIN_CFG(144, GPIO) +#define GPIO144_I2C3_SCL PIN_CFG(144, ALT_A) +#define GPIO144_ETM_D3 PIN_CFG(144, ALT_B) +#define GPIO144_STMAPE_DAT2 PIN_CFG(144, ALT_C) + +#define GPIO145_GPIO PIN_CFG(145, GPIO) +#define GPIO145_I2C3_SDA PIN_CFG(145, ALT_A) +#define GPIO145_ETM_D2 PIN_CFG(145, ALT_B) +#define GPIO145_STMAPE_DAT3 PIN_CFG(145, ALT_C) + +#define GPIO146_GPIO PIN_CFG(146, GPIO) +#define GPIO146_PWM_0 PIN_CFG(146, ALT_A) +#define GPIO146_ETM_D1 PIN_CFG(146, ALT_B) + +#define GPIO147_GPIO PIN_CFG(147, GPIO) +#define GPIO147_PWM_1 PIN_CFG(147, ALT_A) +#define GPIO147_ETM_D0 PIN_CFG(147, ALT_B) + +#define GPIO148_GPIO PIN_CFG(148, GPIO) +#define GPIO148_PWM_2 PIN_CFG(148, ALT_A) +#define GPIO148_ETM_CLK PIN_CFG(148, ALT_B) + +#define GPIO160_GPIO PIN_CFG(160, GPIO) +#define GPIO160_CLKOUT_REQn PIN_CFG(160, ALT_A) + +#define GPIO161_GPIO PIN_CFG(161, GPIO) +#define GPIO161_CLKOUT_0 PIN_CFG(161, ALT_A) + +#define GPIO162_GPIO PIN_CFG(162, GPIO) +#define GPIO162_CLKOUT_1 PIN_CFG(162, ALT_A) + +#define GPIO163_GPIO PIN_CFG(163, GPIO) + +#define GPIO164_GPIO PIN_CFG(164, GPIO) +#define GPIO164_GPS_START PIN_CFG(164, ALT_A) + +#define GPIO165_GPIO PIN_CFG(165, GPIO) +#define GPIO165_SPI1_CS2n PIN_CFG(165, ALT_A) +#define GPIO165_U3_RXD PIN_CFG(165, ALT_B) +#define GPIO165_BUSMON_D20 PIN_CFG(165, ALT_C) + +#define GPIO166_GPIO PIN_CFG(166, GPIO) +#define GPIO166_SPI1_CS1n PIN_CFG(166, ALT_A) +#define GPIO166_U3_TXD PIN_CFG(166, ALT_B) +#define GPIO166_BUSMON_D21 PIN_CFG(166, ALT_C) + +#define GPIO167_GPIO PIN_CFG(167, GPIO) +#define GPIO167_SPI1_CS0n PIN_CFG(167, ALT_A) +#define GPIO167_U3_RTSn PIN_CFG(167, ALT_B) +#define GPIO167_BUSMON_D22 PIN_CFG(167, ALT_C) + +#define GPIO168_GPIO PIN_CFG(168, GPIO) +#define GPIO168_SPI1_RXD PIN_CFG(168, ALT_A) +#define GPIO168_U3_CTSn PIN_CFG(168, ALT_B) +#define GPIO168_BUSMON_D23 PIN_CFG(168, ALT_C) + +#define GPIO169_GPIO PIN_CFG(169, GPIO) +#define GPIO169_SPI1_TXD PIN_CFG(169, ALT_A) +#define GPIO169_DDR_RC PIN_CFG(169, ALT_B) +#define GPIO169_BUSMON_D24 PIN_CFG(169, ALT_C) + +#define GPIO170_GPIO PIN_CFG(170, GPIO) +#define GPIO170_SPI1_CLK PIN_CFG(170, ALT_A) + +#define GPIO171_GPIO PIN_CFG(171, GPIO) +#define GPIO171_MC3_DAT0 PIN_CFG(171, ALT_A) +#define GPIO171_SPI3_RXD PIN_CFG(171, ALT_B) +#define GPIO171_BUSMON_D25 PIN_CFG(171, ALT_C) + +#define GPIO172_GPIO PIN_CFG(172, GPIO) +#define GPIO172_MC3_DAT1 PIN_CFG(172, ALT_A) +#define GPIO172_SPI3_CS1n PIN_CFG(172, ALT_B) +#define GPIO172_BUSMON_D26 PIN_CFG(172, ALT_C) + +#define GPIO173_GPIO PIN_CFG(173, GPIO) +#define GPIO173_MC3_DAT2 PIN_CFG(173, ALT_A) +#define GPIO173_SPI3_CS2n PIN_CFG(173, ALT_B) +#define GPIO173_BUSMON_D27 PIN_CFG(173, ALT_C) + +#define GPIO174_GPIO PIN_CFG(174, GPIO) +#define GPIO174_MC3_DAT3 PIN_CFG(174, ALT_A) +#define GPIO174_SPI3_CS0n PIN_CFG(174, ALT_B) +#define GPIO174_BUSMON_D28 PIN_CFG(174, ALT_C) + +#define GPIO175_GPIO PIN_CFG(175, GPIO) +#define GPIO175_MC3_CMD PIN_CFG(175, ALT_A) +#define GPIO175_SPI3_TXD PIN_CFG(175, ALT_B) +#define GPIO175_BUSMON_D29 PIN_CFG(175, ALT_C) + +#define GPIO176_GPIO PIN_CFG(176, GPIO) +#define GPIO176_MC3_CLK PIN_CFG(176, ALT_A) +#define GPIO176_SPI3_CLK PIN_CFG(176, ALT_B) + +#define GPIO177_GPIO PIN_CFG(177, GPIO) +#define GPIO177_U2_RXD PIN_CFG(177, ALT_A) +#define GPIO177_I2C3_SCL PIN_CFG(177, ALT_B) +#define GPIO177_BUSMON_D30 PIN_CFG(177, ALT_C) + +#define GPIO178_GPIO PIN_CFG(178, GPIO) +#define GPIO178_U2_TXD PIN_CFG(178, ALT_A) +#define GPIO178_I2C3_SDA PIN_CFG(178, ALT_B) +#define GPIO178_BUSMON_D31 PIN_CFG(178, ALT_C) + +#define GPIO179_GPIO PIN_CFG(179, GPIO) +#define GPIO179_U2_CTSn PIN_CFG(179, ALT_A) +#define GPIO179_U3_RXD PIN_CFG(179, ALT_B) +#define GPIO179_BUSMON_D32 PIN_CFG(179, ALT_C) + +#define GPIO180_GPIO PIN_CFG(180, GPIO) +#define GPIO180_U2_RTSn PIN_CFG(180, ALT_A) +#define GPIO180_U3_TXD PIN_CFG(180, ALT_B) +#define GPIO180_BUSMON_D33 PIN_CFG(180, ALT_C) + +#define GPIO185_GPIO PIN_CFG(185, GPIO) +#define GPIO185_SPI3_CS2n PIN_CFG(185, ALT_A) +#define GPIO185_MC4_DAT0 PIN_CFG(185, ALT_B) + +#define GPIO186_GPIO PIN_CFG(186, GPIO) +#define GPIO186_SPI3_CS1n PIN_CFG(186, ALT_A) +#define GPIO186_MC4_DAT1 PIN_CFG(186, ALT_B) + +#define GPIO187_GPIO PIN_CFG(187, GPIO) +#define GPIO187_SPI3_CS0n PIN_CFG(187, ALT_A) +#define GPIO187_MC4_DAT2 PIN_CFG(187, ALT_B) + +#define GPIO188_GPIO PIN_CFG(188, GPIO) +#define GPIO188_SPI3_RXD PIN_CFG(188, ALT_A) +#define GPIO188_MC4_DAT3 PIN_CFG(188, ALT_B) + +#define GPIO189_GPIO PIN_CFG(189, GPIO) +#define GPIO189_SPI3_TXD PIN_CFG(189, ALT_A) +#define GPIO189_MC4_CMD PIN_CFG(189, ALT_B) + +#define GPIO190_GPIO PIN_CFG(190, GPIO) +#define GPIO190_SPI3_CLK PIN_CFG(190, ALT_A) +#define GPIO190_MC4_CLK PIN_CFG(190, ALT_B) + +#define GPIO191_GPIO PIN_CFG(191, GPIO) +#define GPIO191_MC1_DAT0 PIN_CFG(191, ALT_A) +#define GPIO191_MC4_DAT4 PIN_CFG(191, ALT_B) +#define GPIO191_STMAPE_DAT0 PIN_CFG(191, ALT_C) + +#define GPIO192_GPIO PIN_CFG(192, GPIO) +#define GPIO192_MC1_DAT1 PIN_CFG(192, ALT_A) +#define GPIO192_MC4_DAT5 PIN_CFG(192, ALT_B) +#define GPIO192_STMAPE_DAT1 PIN_CFG(192, ALT_C) + +#define GPIO193_GPIO PIN_CFG(193, GPIO) +#define GPIO193_MC1_DAT2 PIN_CFG(193, ALT_A) +#define GPIO193_MC4_DAT6 PIN_CFG(193, ALT_B) +#define GPIO193_STMAPE_DAT2 PIN_CFG(193, ALT_C) + +#define GPIO194_GPIO PIN_CFG(194, GPIO) +#define GPIO194_MC1_DAT3 PIN_CFG(194, ALT_A) +#define GPIO194_MC4_DAT7 PIN_CFG(194, ALT_B) +#define GPIO194_STMAPE_DAT3 PIN_CFG(194, ALT_C) + +#define GPIO195_GPIO PIN_CFG(195, GPIO) +#define GPIO195_MC1_CLK PIN_CFG(195, ALT_A) +#define GPIO195_STMAPE_CLK PIN_CFG(195, ALT_B) +#define GPIO195_BUSMON_CLK PIN_CFG(195, ALT_C) + +#define GPIO196_GPIO PIN_CFG(196, GPIO) +#define GPIO196_MC1_CMD PIN_CFG(196, ALT_A) +#define GPIO196_U0_RXD PIN_CFG(196, ALT_B) +#define GPIO196_BUSMON_D38 PIN_CFG(196, ALT_C) + +#define GPIO197_GPIO PIN_CFG(197, GPIO) +#define GPIO197_MC1_CMDDIR PIN_CFG(197, ALT_A) +#define GPIO197_BUSMON_D39 PIN_CFG(197, ALT_B) + +#define GPIO198_GPIO PIN_CFG(198, GPIO) +#define GPIO198_MC1_FBCLK PIN_CFG(198, ALT_A) + +#define GPIO199_GPIO PIN_CFG(199, GPIO) +#define GPIO199_MC1_DAT0DIR PIN_CFG(199, ALT_A) +#define GPIO199_BUSMON_D40 PIN_CFG(199, ALT_B) + +#define GPIO200_GPIO PIN_CFG(200, GPIO) +#define GPIO200_U1_TXD PIN_CFG(200, ALT_A) +#define GPIO200_ACCU0_RTSn PIN_CFG(200, ALT_B) + +#define GPIO201_GPIO PIN_CFG(201, GPIO) +#define GPIO201_U1_RXD PIN_CFG(201, ALT_A) +#define GPIO201_ACCU0_CTSn PIN_CFG(201, ALT_B) + +#define GPIO202_GPIO PIN_CFG(202, GPIO) +#define GPIO202_U1_CTSn PIN_CFG(202, ALT_A) +#define GPIO202_ACCU0_RXD PIN_CFG(202, ALT_B) + +#define GPIO203_GPIO PIN_CFG(203, GPIO) +#define GPIO203_U1_RTSn PIN_CFG(203, ALT_A) +#define GPIO203_ACCU0_TXD PIN_CFG(203, ALT_B) + +#define GPIO204_GPIO PIN_CFG(204, GPIO) +#define GPIO204_SPI0_CS2n PIN_CFG(204, ALT_A) +#define GPIO204_ACCGPIO_000 PIN_CFG(204, ALT_B) +#define GPIO204_LCD_VSI1 PIN_CFG(204, ALT_C) + +#define GPIO205_GPIO PIN_CFG(205, GPIO) +#define GPIO205_SPI0_CS1n PIN_CFG(205, ALT_A) +#define GPIO205_ACCGPIO_001 PIN_CFG(205, ALT_B) +#define GPIO205_LCD_D3 PIN_CFG(205, ALT_C) + +#define GPIO206_GPIO PIN_CFG(206, GPIO) +#define GPIO206_SPI0_CS0n PIN_CFG(206, ALT_A) +#define GPIO206_ACCGPIO_002 PIN_CFG(206, ALT_B) +#define GPIO206_LCD_D2 PIN_CFG(206, ALT_C) + +#define GPIO207_GPIO PIN_CFG(207, GPIO) +#define GPIO207_SPI0_RXD PIN_CFG(207, ALT_A) +#define GPIO207_ACCGPIO_003 PIN_CFG(207, ALT_B) +#define GPIO207_LCD_D1 PIN_CFG(207, ALT_C) + +#define GPIO208_GPIO PIN_CFG(208, GPIO) +#define GPIO208_SPI0_TXD PIN_CFG(208, ALT_A) +#define GPIO208_ACCGPIO_004 PIN_CFG(208, ALT_B) +#define GPIO208_LCD_D0 PIN_CFG(208, ALT_C) + +#define GPIO209_GPIO PIN_CFG(209, GPIO) +#define GPIO209_SPI0_CLK PIN_CFG(209, ALT_A) +#define GPIO209_ACCGPIO_005 PIN_CFG(209, ALT_B) +#define GPIO209_LCD_CLK PIN_CFG(209, ALT_C) + +#define GPIO210_GPIO PIN_CFG(210, GPIO) +#define GPIO210_LCD_VSO PIN_CFG(210, ALT_A) +#define GPIO210_PRCMU_PWRCTRL1 PIN_CFG(210, ALT_B) + +#define GPIO211_GPIO PIN_CFG(211, GPIO) +#define GPIO211_LCD_VSI0 PIN_CFG(211, ALT_A) +#define GPIO211_PRCMU_PWRCTRL2 PIN_CFG(211, ALT_B) + +#define GPIO212_GPIO PIN_CFG(212, GPIO) +#define GPIO212_SPI2_CS2n PIN_CFG(212, ALT_A) +#define GPIO212_LCD_HSO PIN_CFG(212, ALT_B) + +#define GPIO213_GPIO PIN_CFG(213, GPIO) +#define GPIO213_SPI2_CS1n PIN_CFG(213, ALT_A) +#define GPIO213_LCD_DE PIN_CFG(213, ALT_B) +#define GPIO213_BUSMON_D16 PIN_CFG(213, ALT_C) + +#define GPIO214_GPIO PIN_CFG(214, GPIO) +#define GPIO214_SPI2_CS0n PIN_CFG(214, ALT_A) +#define GPIO214_LCD_D7 PIN_CFG(214, ALT_B) +#define GPIO214_BUSMON_D17 PIN_CFG(214, ALT_C) + +#define GPIO215_GPIO PIN_CFG(215, GPIO) +#define GPIO215_SPI2_RXD PIN_CFG(215, ALT_A) +#define GPIO215_LCD_D6 PIN_CFG(215, ALT_B) +#define GPIO215_BUSMON_D18 PIN_CFG(215, ALT_C) + +#define GPIO216_GPIO PIN_CFG(216, GPIO) +#define GPIO216_SPI2_CLK PIN_CFG(216, ALT_A) +#define GPIO216_LCD_D5 PIN_CFG(216, ALT_B) + +#define GPIO217_GPIO PIN_CFG(217, GPIO) +#define GPIO217_SPI2_TXD PIN_CFG(217, ALT_A) +#define GPIO217_LCD_D4 PIN_CFG(217, ALT_B) +#define GPIO217_BUSMON_D19 PIN_CFG(217, ALT_C) + +#define GPIO218_GPIO PIN_CFG(218, GPIO) +#define GPIO218_I2C2_SCL PIN_CFG(218, ALT_A) +#define GPIO218_LCD_VSO PIN_CFG(218, ALT_B) + +#define GPIO219_GPIO PIN_CFG(219, GPIO) +#define GPIO219_I2C2_SDA PIN_CFG(219, ALT_A) +#define GPIO219_LCD_D3 PIN_CFG(219, ALT_B) + +#define GPIO220_GPIO PIN_CFG(220, GPIO) +#define GPIO220_MSP2_TCK PIN_CFG(220, ALT_A) +#define GPIO220_LCD_D2 PIN_CFG(220, ALT_B) + +#define GPIO221_GPIO PIN_CFG(221, GPIO) +#define GPIO221_MSP2_TFS PIN_CFG(221, ALT_A) +#define GPIO221_LCD_D1 PIN_CFG(221, ALT_B) + +#define GPIO222_GPIO PIN_CFG(222, GPIO) +#define GPIO222_MSP2_TXD PIN_CFG(222, ALT_A) +#define GPIO222_LCD_D0 PIN_CFG(222, ALT_B) + +#define GPIO223_GPIO PIN_CFG(223, GPIO) +#define GPIO223_MSP2_RXD PIN_CFG(223, ALT_A) +#define GPIO223_LCD_CLK PIN_CFG(223, ALT_B) + +#define GPIO224_GPIO PIN_CFG(224, GPIO) +#define GPIO224_PRCMU_PWRCTRL0 PIN_CFG(224, ALT_A) +#define GPIO224_LCD_VSI1 PIN_CFG(224, ALT_B) + +#define GPIO225_GPIO PIN_CFG(225, GPIO) +#define GPIO225_PRCMU_PWRCTRL1 PIN_CFG(225, ALT_A) +#define GPIO225_IRDA_RXD PIN_CFG(225, ALT_B) + +#define GPIO226_GPIO PIN_CFG(226, GPIO) +#define GPIO226_PRCMU_PWRCTRL2 PIN_CFG(226, ALT_A) +#define GPIO226_IRRC_DAT PIN_CFG(226, ALT_B) + +#define GPIO227_GPIO PIN_CFG(227, GPIO) +#define GPIO227_IRRC_DAT PIN_CFG(227, ALT_A) +#define GPIO227_IRDA_TXD PIN_CFG(227, ALT_B) + +#endif diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h new file mode 100644 index 00000000000..062c7acf457 --- /dev/null +++ b/arch/arm/mach-ux500/pins-db8500.h @@ -0,0 +1,746 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License, version 2 + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + */ + +#ifndef __MACH_PINS_DB8500_H +#define __MACH_PINS_DB8500_H + +/* + * TODO: Eventually encode all non-board specific pull up/down configuration + * here. + */ + +#define GPIO0_GPIO PIN_CFG(0, GPIO) +#define GPIO0_U0_CTSn PIN_CFG(0, ALT_A) +#define GPIO0_TRIG_OUT PIN_CFG(0, ALT_B) +#define GPIO0_IP_TDO PIN_CFG(0, ALT_C) + +#define GPIO1_GPIO PIN_CFG(1, GPIO) +#define GPIO1_U0_RTSn PIN_CFG(1, ALT_A) +#define GPIO1_TRIG_IN PIN_CFG(1, ALT_B) +#define GPIO1_IP_TDI PIN_CFG(1, ALT_C) + +#define GPIO2_GPIO PIN_CFG(2, GPIO) +#define GPIO2_U0_RXD PIN_CFG(2, ALT_A) +#define GPIO2_NONE PIN_CFG(2, ALT_B) +#define GPIO2_IP_TMS PIN_CFG(2, ALT_C) + +#define GPIO3_GPIO PIN_CFG(3, GPIO) +#define GPIO3_U0_TXD PIN_CFG(3, ALT_A) +#define GPIO3_NONE PIN_CFG(3, ALT_B) +#define GPIO3_IP_TCK PIN_CFG(3, ALT_C) + +#define GPIO4_GPIO PIN_CFG(4, GPIO) +#define GPIO4_U1_RXD PIN_CFG(4, ALT_A) +#define GPIO4_I2C4_SCL PIN_CFG(4, ALT_B) +#define GPIO4_IP_TRSTn PIN_CFG(4, ALT_C) + +#define GPIO5_GPIO PIN_CFG(5, GPIO) +#define GPIO5_U1_TXD PIN_CFG(5, ALT_A) +#define GPIO5_I2C4_SDA PIN_CFG(5, ALT_B) +#define GPIO5_IP_GPIO6 PIN_CFG(5, ALT_C) + +#define GPIO6_GPIO PIN_CFG(6, GPIO) +#define GPIO6_U1_CTSn PIN_CFG(6, ALT_A) +#define GPIO6_I2C1_SCL PIN_CFG(6, ALT_B) +#define GPIO6_IP_GPIO0 PIN_CFG(6, ALT_C) + +#define GPIO7_GPIO PIN_CFG(7, GPIO) +#define GPIO7_U1_RTSn PIN_CFG(7, ALT_A) +#define GPIO7_I2C1_SDA PIN_CFG(7, ALT_B) +#define GPIO7_IP_GPIO1 PIN_CFG(7, ALT_C) + +#define GPIO8_GPIO PIN_CFG(8, GPIO) +#define GPIO8_IPI2C_SDA PIN_CFG(8, ALT_A) +#define GPIO8_I2C2_SDA PIN_CFG(8, ALT_B) + +#define GPIO9_GPIO PIN_CFG(9, GPIO) +#define GPIO9_IPI2C_SCL PIN_CFG(9, ALT_A) +#define GPIO9_I2C2_SCL PIN_CFG(9, ALT_B) + +#define GPIO10_GPIO PIN_CFG(10, GPIO) +#define GPIO10_IPI2C_SDA PIN_CFG(10, ALT_A) +#define GPIO10_I2C2_SDA PIN_CFG(10, ALT_B) +#define GPIO10_IP_GPIO3 PIN_CFG(10, ALT_C) + +#define GPIO11_GPIO PIN_CFG(11, GPIO) +#define GPIO11_IPI2C_SCL PIN_CFG(11, ALT_A) +#define GPIO11_I2C2_SCL PIN_CFG(11, ALT_B) +#define GPIO11_IP_GPIO2 PIN_CFG(11, ALT_C) + +#define GPIO12_GPIO PIN_CFG(12, GPIO) +#define GPIO12_MSP0_TXD PIN_CFG(12, ALT_A) +#define GPIO12_MSP0_RXD PIN_CFG(12, ALT_B) + +#define GPIO13_GPIO PIN_CFG(13, GPIO) +#define GPIO13_MSP0_TFS PIN_CFG(13, ALT_A) + +#define GPIO14_GPIO PIN_CFG(14, GPIO) +#define GPIO14_MSP0_TCK PIN_CFG(14, ALT_A) + +#define GPIO15_GPIO PIN_CFG(15, GPIO) +#define GPIO15_MSP0_RXD PIN_CFG(15, ALT_A) +#define GPIO15_MSP0_TXD PIN_CFG(15, ALT_B) + +#define GPIO16_GPIO PIN_CFG(16, GPIO) +#define GPIO16_MSP0_RFS PIN_CFG(16, ALT_A) +#define GPIO16_I2C1_SCL PIN_CFG(16, ALT_B) +#define GPIO16_SLIM0_DAT PIN_CFG(16, ALT_C) + +#define GPIO17_GPIO PIN_CFG(17, GPIO) +#define GPIO17_MSP0_RCK PIN_CFG(17, ALT_A) +#define GPIO17_I2C1_SDA PIN_CFG(17, ALT_B) +#define GPIO17_SLIM0_CLK PIN_CFG(17, ALT_C) + +#define GPIO18_GPIO PIN_CFG(18, GPIO) +#define GPIO18_MC0_CMDDIR PIN_CFG_INPUT(18, ALT_A, PULLUP) +#define GPIO18_U2_RXD PIN_CFG(18, ALT_B) +#define GPIO18_MS_IEP PIN_CFG(18, ALT_C) + +#define GPIO19_GPIO PIN_CFG(19, GPIO) +#define GPIO19_MC0_DAT0DIR PIN_CFG_INPUT(19, ALT_A, PULLUP) +#define GPIO19_U2_TXD PIN_CFG(19, ALT_B) +#define GPIO19_MS_DAT0DIR PIN_CFG(19, ALT_C) + +#define GPIO20_GPIO PIN_CFG(20, GPIO) +#define GPIO20_MC0_DAT2DIR PIN_CFG_INPUT(20, ALT_A, PULLUP) +#define GPIO20_UARTMOD_TXD PIN_CFG(20, ALT_B) +#define GPIO20_IP_TRIGOUT PIN_CFG(20, ALT_C) + +#define GPIO21_GPIO PIN_CFG(21, GPIO) +#define GPIO21_MC0_DAT31DIR PIN_CFG_INPUT(21, ALT_A, PULLUP) +#define GPIO21_MSP0_SCK PIN_CFG(21, ALT_B) +#define GPIO21_MS_DAT31DIR PIN_CFG(21, ALT_C) + +#define GPIO22_GPIO PIN_CFG(22, GPIO) +#define GPIO22_MC0_FBCLK PIN_CFG_INPUT(22, ALT_A, PULLUP) +#define GPIO22_UARTMOD_RXD PIN_CFG(22, ALT_B) +#define GPIO22_MS_FBCLK PIN_CFG(22, ALT_C) + +#define GPIO23_GPIO PIN_CFG(23, GPIO) +#define GPIO23_MC0_CLK PIN_CFG_INPUT(23, ALT_A, PULLUP) +#define GPIO23_STMMOD_CLK PIN_CFG(23, ALT_B) +#define GPIO23_MS_CLK PIN_CFG(23, ALT_C) + +#define GPIO24_GPIO PIN_CFG(24, GPIO) +#define GPIO24_MC0_CMD PIN_CFG_INPUT(24, ALT_A, PULLUP) +#define GPIO24_UARTMOD_RXD PIN_CFG(24, ALT_B) +#define GPIO24_MS_BS PIN_CFG(24, ALT_C) + +#define GPIO25_GPIO PIN_CFG(25, GPIO) +#define GPIO25_MC0_DAT0 PIN_CFG_INPUT(25, ALT_A, PULLUP) +#define GPIO25_STMMOD_DAT0 PIN_CFG(25, ALT_B) +#define GPIO25_MS_DAT0 PIN_CFG(25, ALT_C) + +#define GPIO26_GPIO PIN_CFG(26, GPIO) +#define GPIO26_MC0_DAT1 PIN_CFG_INPUT(26, ALT_A, PULLUP) +#define GPIO26_STMMOD_DAT1 PIN_CFG(26, ALT_B) +#define GPIO26_MS_DAT1 PIN_CFG(26, ALT_C) + +#define GPIO27_GPIO PIN_CFG(27, GPIO) +#define GPIO27_MC0_DAT2 PIN_CFG_INPUT(27, ALT_A, PULLUP) +#define GPIO27_STMMOD_DAT2 PIN_CFG(27, ALT_B) +#define GPIO27_MS_DAT2 PIN_CFG(27, ALT_C) + +#define GPIO28_GPIO PIN_CFG(28, GPIO) +#define GPIO28_MC0_DAT3 PIN_CFG_INPUT(28, ALT_A, PULLUP) +#define GPIO28_STMMOD_DAT3 PIN_CFG(28, ALT_B) +#define GPIO28_MS_DAT3 PIN_CFG(28, ALT_C) + +#define GPIO29_GPIO PIN_CFG(29, GPIO) +#define GPIO29_MC0_DAT4 PIN_CFG(29, ALT_A) +#define GPIO29_SPI3_CLK PIN_CFG(29, ALT_B) +#define GPIO29_U2_RXD PIN_CFG(29, ALT_C) + +#define GPIO30_GPIO PIN_CFG(30, GPIO) +#define GPIO30_MC0_DAT5 PIN_CFG(30, ALT_A) +#define GPIO30_SPI3_RXD PIN_CFG(30, ALT_B) +#define GPIO30_U2_TXD PIN_CFG(30, ALT_C) + +#define GPIO31_GPIO PIN_CFG(31, GPIO) +#define GPIO31_MC0_DAT6 PIN_CFG(31, ALT_A) +#define GPIO31_SPI3_FRM PIN_CFG(31, ALT_B) +#define GPIO31_U2_CTSn PIN_CFG(31, ALT_C) + +#define GPIO32_GPIO PIN_CFG(32, GPIO) +#define GPIO32_MC0_DAT7 PIN_CFG(32, ALT_A) +#define GPIO32_SPI3_TXD PIN_CFG(32, ALT_B) +#define GPIO32_U2_RTSn PIN_CFG(32, ALT_C) + +#define GPIO33_GPIO PIN_CFG(33, GPIO) +#define GPIO33_MSP1_TXD PIN_CFG(33, ALT_A) +#define GPIO33_MSP1_RXD PIN_CFG(33, ALT_B) +#define GPIO33_U0_DTRn PIN_CFG(33, ALT_C) + +#define GPIO34_GPIO PIN_CFG(34, GPIO) +#define GPIO34_MSP1_TFS PIN_CFG(34, ALT_A) +#define GPIO34_NONE PIN_CFG(34, ALT_B) +#define GPIO34_U0_DCDn PIN_CFG(34, ALT_C) + +#define GPIO35_GPIO PIN_CFG(35, GPIO) +#define GPIO35_MSP1_TCK PIN_CFG(35, ALT_A) +#define GPIO35_NONE PIN_CFG(35, ALT_B) +#define GPIO35_U0_DSRn PIN_CFG(35, ALT_C) + +#define GPIO36_GPIO PIN_CFG(36, GPIO) +#define GPIO36_MSP1_RXD PIN_CFG(36, ALT_A) +#define GPIO36_MSP1_TXD PIN_CFG(36, ALT_B) +#define GPIO36_U0_RIn PIN_CFG(36, ALT_C) + +#define GPIO64_GPIO PIN_CFG(64, GPIO) +#define GPIO64_LCDB_DE PIN_CFG(64, ALT_A) +#define GPIO64_KP_O1 PIN_CFG(64, ALT_B) +#define GPIO64_IP_GPIO4 PIN_CFG(64, ALT_C) + +#define GPIO65_GPIO PIN_CFG(65, GPIO) +#define GPIO65_LCDB_HSO PIN_CFG(65, ALT_A) +#define GPIO65_KP_O0 PIN_CFG(65, ALT_B) +#define GPIO65_IP_GPIO5 PIN_CFG(65, ALT_C) + +#define GPIO66_GPIO PIN_CFG(66, GPIO) +#define GPIO66_LCDB_VSO PIN_CFG(66, ALT_A) +#define GPIO66_KP_I1 PIN_CFG(66, ALT_B) +#define GPIO66_IP_GPIO6 PIN_CFG(66, ALT_C) + +#define GPIO67_GPIO PIN_CFG(67, GPIO) +#define GPIO67_LCDB_CLK PIN_CFG(67, ALT_A) +#define GPIO67_KP_I0 PIN_CFG(67, ALT_B) +#define GPIO67_IP_GPIO7 PIN_CFG(67, ALT_C) + +#define GPIO68_GPIO PIN_CFG(68, GPIO) +#define GPIO68_LCD_VSI0 PIN_CFG(68, ALT_A) +#define GPIO68_KP_O7 PIN_CFG(68, ALT_B) +#define GPIO68_SM_CLE PIN_CFG(68, ALT_C) + +#define GPIO69_GPIO PIN_CFG(69, GPIO) +#define GPIO69_LCD_VSI1 PIN_CFG(69, ALT_A) +#define GPIO69_KP_I7 PIN_CFG(69, ALT_B) +#define GPIO69_SM_ALE PIN_CFG(69, ALT_C) + +#define GPIO70_GPIO PIN_CFG(70, GPIO) +#define GPIO70_LCD_D0 PIN_CFG(70, ALT_A) +#define GPIO70_KP_O5 PIN_CFG(70, ALT_B) +#define GPIO70_STMAPE_CLK PIN_CFG(70, ALT_C) + +#define GPIO71_GPIO PIN_CFG(71, GPIO) +#define GPIO71_LCD_D1 PIN_CFG(71, ALT_A) +#define GPIO71_KP_O4 PIN_CFG(71, ALT_B) +#define GPIO71_STMAPE_DAT3 PIN_CFG(71, ALT_C) + +#define GPIO72_GPIO PIN_CFG(72, GPIO) +#define GPIO72_LCD_D2 PIN_CFG(72, ALT_A) +#define GPIO72_KP_O3 PIN_CFG(72, ALT_B) +#define GPIO72_STMAPE_DAT2 PIN_CFG(72, ALT_C) + +#define GPIO73_GPIO PIN_CFG(73, GPIO) +#define GPIO73_LCD_D3 PIN_CFG(73, ALT_A) +#define GPIO73_KP_O2 PIN_CFG(73, ALT_B) +#define GPIO73_STMAPE_DAT1 PIN_CFG(73, ALT_C) + +#define GPIO74_GPIO PIN_CFG(74, GPIO) +#define GPIO74_LCD_D4 PIN_CFG(74, ALT_A) +#define GPIO74_KP_I5 PIN_CFG(74, ALT_B) +#define GPIO74_STMAPE_DAT0 PIN_CFG(74, ALT_C) + +#define GPIO75_GPIO PIN_CFG(75, GPIO) +#define GPIO75_LCD_D5 PIN_CFG(75, ALT_A) +#define GPIO75_KP_I4 PIN_CFG(75, ALT_B) +#define GPIO75_U2_RXD PIN_CFG(75, ALT_C) + +#define GPIO76_GPIO PIN_CFG(76, GPIO) +#define GPIO76_LCD_D6 PIN_CFG(76, ALT_A) +#define GPIO76_KP_I3 PIN_CFG(76, ALT_B) +#define GPIO76_U2_TXD PIN_CFG(76, ALT_C) + +#define GPIO77_GPIO PIN_CFG(77, GPIO) +#define GPIO77_LCD_D7 PIN_CFG(77, ALT_A) +#define GPIO77_KP_I2 PIN_CFG(77, ALT_B) +#define GPIO77_NONE PIN_CFG(77, ALT_C) + +#define GPIO78_GPIO PIN_CFG(78, GPIO) +#define GPIO78_LCD_D8 PIN_CFG(78, ALT_A) +#define GPIO78_KP_O6 PIN_CFG(78, ALT_B) +#define GPIO78_IP_GPIO2 PIN_CFG(78, ALT_C) + +#define GPIO79_GPIO PIN_CFG(79, GPIO) +#define GPIO79_LCD_D9 PIN_CFG(79, ALT_A) +#define GPIO79_KP_I6 PIN_CFG(79, ALT_B) +#define GPIO79_IP_GPIO3 PIN_CFG(79, ALT_C) + +#define GPIO80_GPIO PIN_CFG(80, GPIO) +#define GPIO80_LCD_D10 PIN_CFG(80, ALT_A) +#define GPIO80_KP_SKA0 PIN_CFG(80, ALT_B) +#define GPIO80_IP_GPIO4 PIN_CFG(80, ALT_C) + +#define GPIO81_GPIO PIN_CFG(81, GPIO) +#define GPIO81_LCD_D11 PIN_CFG(81, ALT_A) +#define GPIO81_KP_SKB0 PIN_CFG(81, ALT_B) +#define GPIO81_IP_GPIO5 PIN_CFG(81, ALT_C) + +#define GPIO82_GPIO PIN_CFG(82, GPIO) +#define GPIO82_LCD_D12 PIN_CFG(82, ALT_A) +#define GPIO82_KP_O5 PIN_CFG(82, ALT_B) + +#define GPIO83_GPIO PIN_CFG(83, GPIO) +#define GPIO83_LCD_D13 PIN_CFG(83, ALT_A) +#define GPIO83_KP_O4 PIN_CFG(83, ALT_B) + +#define GPIO84_GPIO PIN_CFG(84, GPIO) +#define GPIO84_LCD_D14 PIN_CFG(84, ALT_A) +#define GPIO84_KP_I5 PIN_CFG(84, ALT_B) + +#define GPIO85_GPIO PIN_CFG(85, GPIO) +#define GPIO85_LCD_D15 PIN_CFG(85, ALT_A) +#define GPIO85_KP_I4 PIN_CFG(85, ALT_B) + +#define GPIO86_GPIO PIN_CFG(86, GPIO) +#define GPIO86_LCD_D16 PIN_CFG(86, ALT_A) +#define GPIO86_SM_ADQ0 PIN_CFG(86, ALT_B) +#define GPIO86_MC5_DAT0 PIN_CFG(86, ALT_C) + +#define GPIO87_GPIO PIN_CFG(87, GPIO) +#define GPIO87_LCD_D17 PIN_CFG(87, ALT_A) +#define GPIO87_SM_ADQ1 PIN_CFG(87, ALT_B) +#define GPIO87_MC5_DAT1 PIN_CFG(87, ALT_C) + +#define GPIO88_GPIO PIN_CFG(88, GPIO) +#define GPIO88_LCD_D18 PIN_CFG(88, ALT_A) +#define GPIO88_SM_ADQ2 PIN_CFG(88, ALT_B) +#define GPIO88_MC5_DAT2 PIN_CFG(88, ALT_C) + +#define GPIO89_GPIO PIN_CFG(89, GPIO) +#define GPIO89_LCD_D19 PIN_CFG(89, ALT_A) +#define GPIO89_SM_ADQ3 PIN_CFG(89, ALT_B) +#define GPIO89_MC5_DAT3 PIN_CFG(89, ALT_C) + +#define GPIO90_GPIO PIN_CFG(90, GPIO) +#define GPIO90_LCD_D20 PIN_CFG(90, ALT_A) +#define GPIO90_SM_ADQ4 PIN_CFG(90, ALT_B) +#define GPIO90_MC5_CMD PIN_CFG(90, ALT_C) + +#define GPIO91_GPIO PIN_CFG(91, GPIO) +#define GPIO91_LCD_D21 PIN_CFG(91, ALT_A) +#define GPIO91_SM_ADQ5 PIN_CFG(91, ALT_B) +#define GPIO91_MC5_FBCLK PIN_CFG(91, ALT_C) + +#define GPIO92_GPIO PIN_CFG(92, GPIO) +#define GPIO92_LCD_D22 PIN_CFG(92, ALT_A) +#define GPIO92_SM_ADQ6 PIN_CFG(92, ALT_B) +#define GPIO92_MC5_CLK PIN_CFG(92, ALT_C) + +#define GPIO93_GPIO PIN_CFG(93, GPIO) +#define GPIO93_LCD_D23 PIN_CFG(93, ALT_A) +#define GPIO93_SM_ADQ7 PIN_CFG(93, ALT_B) +#define GPIO93_MC5_DAT4 PIN_CFG(93, ALT_C) + +#define GPIO94_GPIO PIN_CFG(94, GPIO) +#define GPIO94_KP_O7 PIN_CFG(94, ALT_A) +#define GPIO94_SM_ADVn PIN_CFG(94, ALT_B) +#define GPIO94_MC5_DAT5 PIN_CFG(94, ALT_C) + +#define GPIO95_GPIO PIN_CFG(95, GPIO) +#define GPIO95_KP_I7 PIN_CFG(95, ALT_A) +#define GPIO95_SM_CS0n PIN_CFG(95, ALT_B) +#define GPIO95_SM_PS0n PIN_CFG(95, ALT_C) + +#define GPIO96_GPIO PIN_CFG(96, GPIO) +#define GPIO96_KP_O6 PIN_CFG(96, ALT_A) +#define GPIO96_SM_OEn PIN_CFG(96, ALT_B) +#define GPIO96_MC5_DAT6 PIN_CFG(96, ALT_C) + +#define GPIO97_GPIO PIN_CFG(97, GPIO) +#define GPIO97_KP_I6 PIN_CFG(97, ALT_A) +#define GPIO97_SM_WEn PIN_CFG(97, ALT_B) +#define GPIO97_MC5_DAT7 PIN_CFG(97, ALT_C) + +#define GPIO128_GPIO PIN_CFG(128, GPIO) +#define GPIO128_MC2_CLK PIN_CFG_INPUT(128, ALT_A, PULLUP) +#define GPIO128_SM_CKO PIN_CFG(128, ALT_B) + +#define GPIO129_GPIO PIN_CFG(129, GPIO) +#define GPIO129_MC2_CMD PIN_CFG_INPUT(129, ALT_A, PULLUP) +#define GPIO129_SM_WAIT0n PIN_CFG(129, ALT_B) + +#define GPIO130_GPIO PIN_CFG(130, GPIO) +#define GPIO130_MC2_FBCLK PIN_CFG_INPUT(130, ALT_A, PULLUP) +#define GPIO130_SM_FBCLK PIN_CFG(130, ALT_B) +#define GPIO130_MC2_RSTN PIN_CFG(130, ALT_C) + +#define GPIO131_GPIO PIN_CFG(131, GPIO) +#define GPIO131_MC2_DAT0 PIN_CFG_INPUT(131, ALT_A, PULLUP) +#define GPIO131_SM_ADQ8 PIN_CFG(131, ALT_B) + +#define GPIO132_GPIO PIN_CFG(132, GPIO) +#define GPIO132_MC2_DAT1 PIN_CFG_INPUT(132, ALT_A, PULLUP) +#define GPIO132_SM_ADQ9 PIN_CFG(132, ALT_B) + +#define GPIO133_GPIO PIN_CFG(133, GPIO) +#define GPIO133_MC2_DAT2 PIN_CFG_INPUT(133, ALT_A, PULLUP) +#define GPIO133_SM_ADQ10 PIN_CFG(133, ALT_B) + +#define GPIO134_GPIO PIN_CFG(134, GPIO) +#define GPIO134_MC2_DAT3 PIN_CFG_INPUT(134, ALT_A, PULLUP) +#define GPIO134_SM_ADQ11 PIN_CFG(134, ALT_B) + +#define GPIO135_GPIO PIN_CFG(135, GPIO) +#define GPIO135_MC2_DAT4 PIN_CFG_INPUT(135, ALT_A, PULLUP) +#define GPIO135_SM_ADQ12 PIN_CFG(135, ALT_B) + +#define GPIO136_GPIO PIN_CFG(136, GPIO) +#define GPIO136_MC2_DAT5 PIN_CFG_INPUT(136, ALT_A, PULLUP) +#define GPIO136_SM_ADQ13 PIN_CFG(136, ALT_B) + +#define GPIO137_GPIO PIN_CFG(137, GPIO) +#define GPIO137_MC2_DAT6 PIN_CFG_INPUT(137, ALT_A, PULLUP) +#define GPIO137_SM_ADQ14 PIN_CFG(137, ALT_B) + +#define GPIO138_GPIO PIN_CFG(138, GPIO) +#define GPIO138_MC2_DAT7 PIN_CFG_INPUT(138, ALT_A, PULLUP) +#define GPIO138_SM_ADQ15 PIN_CFG(138, ALT_B) + +#define GPIO139_GPIO PIN_CFG(139, GPIO) +#define GPIO139_SSP1_RXD PIN_CFG(139, ALT_A) +#define GPIO139_SM_WAIT1n PIN_CFG(139, ALT_B) +#define GPIO139_KP_O8 PIN_CFG(139, ALT_C) + +#define GPIO140_GPIO PIN_CFG(140, GPIO) +#define GPIO140_SSP1_TXD PIN_CFG(140, ALT_A) +#define GPIO140_IP_GPIO7 PIN_CFG(140, ALT_B) +#define GPIO140_KP_SKA1 PIN_CFG(140, ALT_C) + +#define GPIO141_GPIO PIN_CFG(141, GPIO) +#define GPIO141_SSP1_CLK PIN_CFG(141, ALT_A) +#define GPIO141_IP_GPIO2 PIN_CFG(141, ALT_B) +#define GPIO141_KP_O9 PIN_CFG(141, ALT_C) + +#define GPIO142_GPIO PIN_CFG(142, GPIO) +#define GPIO142_SSP1_FRM PIN_CFG(142, ALT_A) +#define GPIO142_IP_GPIO3 PIN_CFG(142, ALT_B) +#define GPIO142_KP_SKB1 PIN_CFG(142, ALT_C) + +#define GPIO143_GPIO PIN_CFG(143, GPIO) +#define GPIO143_SSP0_CLK PIN_CFG(143, ALT_A) + +#define GPIO144_GPIO PIN_CFG(144, GPIO) +#define GPIO144_SSP0_FRM PIN_CFG(144, ALT_A) + +#define GPIO145_GPIO PIN_CFG(145, GPIO) +#define GPIO145_SSP0_RXD PIN_CFG(145, ALT_A) + +#define GPIO146_GPIO PIN_CFG(146, GPIO) +#define GPIO146_SSP0_TXD PIN_CFG(146, ALT_A) + +#define GPIO147_GPIO PIN_CFG(147, GPIO) +#define GPIO147_I2C0_SCL PIN_CFG(147, ALT_A) + +#define GPIO148_GPIO PIN_CFG(148, GPIO) +#define GPIO148_I2C0_SDA PIN_CFG(148, ALT_A) + +#define GPIO149_GPIO PIN_CFG(149, GPIO) +#define GPIO149_IP_GPIO0 PIN_CFG(149, ALT_A) +#define GPIO149_SM_CS1n PIN_CFG(149, ALT_B) +#define GPIO149_SM_PS1n PIN_CFG(149, ALT_C) + +#define GPIO150_GPIO PIN_CFG(150, GPIO) +#define GPIO150_IP_GPIO1 PIN_CFG(150, ALT_A) +#define GPIO150_LCDA_CLK PIN_CFG(150, ALT_B) + +#define GPIO151_GPIO PIN_CFG(151, GPIO) +#define GPIO151_KP_SKA0 PIN_CFG(151, ALT_A) +#define GPIO151_LCD_VSI0 PIN_CFG(151, ALT_B) +#define GPIO151_KP_O8 PIN_CFG(151, ALT_C) + +#define GPIO152_GPIO PIN_CFG(152, GPIO) +#define GPIO152_KP_SKB0 PIN_CFG(152, ALT_A) +#define GPIO152_LCD_VSI1 PIN_CFG(152, ALT_B) +#define GPIO152_KP_O9 PIN_CFG(152, ALT_C) + +#define GPIO153_GPIO PIN_CFG(153, GPIO) +#define GPIO153_KP_I7 PIN_CFG(153, ALT_A) +#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B) +#define GPIO153_U2_RXD PIN_CFG(153, ALT_C) + +#define GPIO154_GPIO PIN_CFG(154, GPIO) +#define GPIO154_KP_I6 PIN_CFG(154, ALT_A) +#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B) +#define GPIO154_U2_TXD PIN_CFG(154, ALT_C) + +#define GPIO155_GPIO PIN_CFG(155, GPIO) +#define GPIO155_KP_I5 PIN_CFG(155, ALT_A) +#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B) +#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C) + +#define GPIO156_GPIO PIN_CFG(156, GPIO) +#define GPIO156_KP_I4 PIN_CFG(156, ALT_A) +#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B) +#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C) + +#define GPIO157_GPIO PIN_CFG(157, GPIO) +#define GPIO157_KP_O7 PIN_CFG(157, ALT_A) +#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B) +#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C) + +#define GPIO158_GPIO PIN_CFG(158, GPIO) +#define GPIO158_KP_O6 PIN_CFG(158, ALT_A) +#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B) +#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C) + +#define GPIO159_GPIO PIN_CFG(159, GPIO) +#define GPIO159_KP_O5 PIN_CFG(159, ALT_A) +#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B) +#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C) + +#define GPIO160_GPIO PIN_CFG(160, GPIO) +#define GPIO160_KP_O4 PIN_CFG(160, ALT_A) +#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B) +#define GPIO160_NONE PIN_CFG(160, ALT_C) + +#define GPIO161_GPIO PIN_CFG(161, GPIO) +#define GPIO161_KP_I3 PIN_CFG(161, ALT_A) +#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B) +#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C) + +#define GPIO162_GPIO PIN_CFG(162, GPIO) +#define GPIO162_KP_I2 PIN_CFG(162, ALT_A) +#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B) +#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C) + +#define GPIO163_GPIO PIN_CFG(163, GPIO) +#define GPIO163_KP_I1 PIN_CFG(163, ALT_A) +#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B) +#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C) + +#define GPIO164_GPIO PIN_CFG(164, GPIO) +#define GPIO164_KP_I0 PIN_CFG(164, ALT_A) +#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B) +#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C) + +#define GPIO165_GPIO PIN_CFG(165, GPIO) +#define GPIO165_KP_O3 PIN_CFG(165, ALT_A) +#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B) +#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C) + +#define GPIO166_GPIO PIN_CFG(166, GPIO) +#define GPIO166_KP_O2 PIN_CFG(166, ALT_A) +#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B) +#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C) + +#define GPIO167_GPIO PIN_CFG(167, GPIO) +#define GPIO167_KP_O1 PIN_CFG(167, ALT_A) +#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B) +#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C) + +#define GPIO168_GPIO PIN_CFG(168, GPIO) +#define GPIO168_KP_O0 PIN_CFG(168, ALT_A) +#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B) +#define GPIO168_NONE PIN_CFG(168, ALT_C) + +#define GPIO169_GPIO PIN_CFG(169, GPIO) +#define GPIO169_RF_PURn PIN_CFG(169, ALT_A) +#define GPIO169_LCDA_DE PIN_CFG(169, ALT_B) +#define GPIO169_USBSIM_PDC PIN_CFG(169, ALT_C) + +#define GPIO170_GPIO PIN_CFG(170, GPIO) +#define GPIO170_MODEM_STATE PIN_CFG(170, ALT_A) +#define GPIO170_LCDA_VSO PIN_CFG(170, ALT_B) +#define GPIO170_KP_SKA1 PIN_CFG(170, ALT_C) + +#define GPIO171_GPIO PIN_CFG(171, GPIO) +#define GPIO171_MODEM_PWREN PIN_CFG(171, ALT_A) +#define GPIO171_LCDA_HSO PIN_CFG(171, ALT_B) +#define GPIO171_KP_SKB1 PIN_CFG(171, ALT_C) + +#define GPIO192_GPIO PIN_CFG(192, GPIO) +#define GPIO192_MSP2_SCK PIN_CFG(192, ALT_A) + +#define GPIO193_GPIO PIN_CFG(193, GPIO) +#define GPIO193_MSP2_TXD PIN_CFG(193, ALT_A) + +#define GPIO194_GPIO PIN_CFG(194, GPIO) +#define GPIO194_MSP2_TCK PIN_CFG(194, ALT_A) + +#define GPIO195_GPIO PIN_CFG(195, GPIO) +#define GPIO195_MSP2_TFS PIN_CFG(195, ALT_A) + +#define GPIO196_GPIO PIN_CFG(196, GPIO) +#define GPIO196_MSP2_RXD PIN_CFG(196, ALT_A) + +#define GPIO197_GPIO PIN_CFG(197, GPIO) +#define GPIO197_MC4_DAT3 PIN_CFG_INPUT(197, ALT_A, PULLUP) + +#define GPIO198_GPIO PIN_CFG(198, GPIO) +#define GPIO198_MC4_DAT2 PIN_CFG_INPUT(198, ALT_A, PULLUP) + +#define GPIO199_GPIO PIN_CFG(199, GPIO) +#define GPIO199_MC4_DAT1 PIN_CFG_INPUT(199, ALT_A, PULLUP) + +#define GPIO200_GPIO PIN_CFG(200, GPIO) +#define GPIO200_MC4_DAT0 PIN_CFG_INPUT(200, ALT_A, PULLUP) + +#define GPIO201_GPIO PIN_CFG(201, GPIO) +#define GPIO201_MC4_CMD PIN_CFG_INPUT(201, ALT_A, PULLUP) + +#define GPIO202_GPIO PIN_CFG(202, GPIO) +#define GPIO202_MC4_FBCLK PIN_CFG_INPUT(202, ALT_A, PULLUP) +#define GPIO202_PWL PIN_CFG(202, ALT_B) +#define GPIO202_MC4_RSTN PIN_CFG(202, ALT_C) + +#define GPIO203_GPIO PIN_CFG(203, GPIO) +#define GPIO203_MC4_CLK PIN_CFG_INPUT(203, ALT_A, PULLUP) + +#define GPIO204_GPIO PIN_CFG(204, GPIO) +#define GPIO204_MC4_DAT7 PIN_CFG_INPUT(204, ALT_A, PULLUP) + +#define GPIO205_GPIO PIN_CFG(205, GPIO) +#define GPIO205_MC4_DAT6 PIN_CFG_INPUT(205, ALT_A, PULLUP) + +#define GPIO206_GPIO PIN_CFG(206, GPIO) +#define GPIO206_MC4_DAT5 PIN_CFG_INPUT(206, ALT_A, PULLUP) + +#define GPIO207_GPIO PIN_CFG(207, GPIO) +#define GPIO207_MC4_DAT4 PIN_CFG_INPUT(207, ALT_A, PULLUP) + +#define GPIO208_GPIO PIN_CFG(208, GPIO) +#define GPIO208_MC1_CLK PIN_CFG(208, ALT_A) + +#define GPIO209_GPIO PIN_CFG(209, GPIO) +#define GPIO209_MC1_FBCLK PIN_CFG(209, ALT_A) +#define GPIO209_SPI1_CLK PIN_CFG(209, ALT_B) + +#define GPIO210_GPIO PIN_CFG(210, GPIO) +#define GPIO210_MC1_CMD PIN_CFG(210, ALT_A) + +#define GPIO211_GPIO PIN_CFG(211, GPIO) +#define GPIO211_MC1_DAT0 PIN_CFG(211, ALT_A) + +#define GPIO212_GPIO PIN_CFG(212, GPIO) +#define GPIO212_MC1_DAT1 PIN_CFG(212, ALT_A) +#define GPIO212_SPI1_FRM PIN_CFG(212, ALT_B) + +#define GPIO213_GPIO PIN_CFG(213, GPIO) +#define GPIO213_MC1_DAT2 PIN_CFG(213, ALT_A) +#define GPIO213_SPI1_TXD PIN_CFG(213, ALT_B) + +#define GPIO214_GPIO PIN_CFG(214, GPIO) +#define GPIO214_MC1_DAT3 PIN_CFG(214, ALT_A) +#define GPIO214_SPI1_RXD PIN_CFG(214, ALT_B) + +#define GPIO215_GPIO PIN_CFG(215, GPIO) +#define GPIO215_MC1_CMDDIR PIN_CFG(215, ALT_A) +#define GPIO215_MC3_DAT2DIR PIN_CFG(215, ALT_B) +#define GPIO215_CLKOUT1 PIN_CFG(215, ALT_C) +#define GPIO215_SPI2_TXD PIN_CFG(215, ALT_C) + +#define GPIO216_GPIO PIN_CFG(216, GPIO) +#define GPIO216_MC1_DAT2DIR PIN_CFG(216, ALT_A) +#define GPIO216_MC3_CMDDIR PIN_CFG(216, ALT_B) +#define GPIO216_I2C3_SDA PIN_CFG(216, ALT_C) +#define GPIO216_SPI2_FRM PIN_CFG(216, ALT_C) + +#define GPIO217_GPIO PIN_CFG(217, GPIO) +#define GPIO217_MC1_DAT0DIR PIN_CFG(217, ALT_A) +#define GPIO217_MC3_DAT31DIR PIN_CFG(217, ALT_B) +#define GPIO217_CLKOUT2 PIN_CFG(217, ALT_C) +#define GPIO217_SPI2_CLK PIN_CFG(217, ALT_C) + +#define GPIO218_GPIO PIN_CFG(218, GPIO) +#define GPIO218_MC1_DAT31DIR PIN_CFG(218, ALT_A) +#define GPIO218_MC3_DAT0DIR PIN_CFG(218, ALT_B) +#define GPIO218_I2C3_SCL PIN_CFG(218, ALT_C) +#define GPIO218_SPI2_RXD PIN_CFG(218, ALT_C) + +#define GPIO219_GPIO PIN_CFG(219, GPIO) +#define GPIO219_HSIR_FLA0 PIN_CFG(219, ALT_A) +#define GPIO219_MC3_CLK PIN_CFG(219, ALT_B) + +#define GPIO220_GPIO PIN_CFG(220, GPIO) +#define GPIO220_HSIR_DAT0 PIN_CFG(220, ALT_A) +#define GPIO220_MC3_FBCLK PIN_CFG(220, ALT_B) +#define GPIO220_SPI0_CLK PIN_CFG(220, ALT_C) + +#define GPIO221_GPIO PIN_CFG(221, GPIO) +#define GPIO221_HSIR_RDY0 PIN_CFG(221, ALT_A) +#define GPIO221_MC3_CMD PIN_CFG(221, ALT_B) + +#define GPIO222_GPIO PIN_CFG(222, GPIO) +#define GPIO222_HSIT_FLA0 PIN_CFG(222, ALT_A) +#define GPIO222_MC3_DAT0 PIN_CFG(222, ALT_B) + +#define GPIO223_GPIO PIN_CFG(223, GPIO) +#define GPIO223_HSIT_DAT0 PIN_CFG(223, ALT_A) +#define GPIO223_MC3_DAT1 PIN_CFG(223, ALT_B) +#define GPIO223_SPI0_FRM PIN_CFG(223, ALT_C) + +#define GPIO224_GPIO PIN_CFG(224, GPIO) +#define GPIO224_HSIT_RDY0 PIN_CFG(224, ALT_A) +#define GPIO224_MC3_DAT2 PIN_CFG(224, ALT_B) +#define GPIO224_SPI0_TXD PIN_CFG(224, ALT_C) + +#define GPIO225_GPIO PIN_CFG(225, GPIO) +#define GPIO225_HSIT_CAWAKE0 PIN_CFG(225, ALT_A) +#define GPIO225_MC3_DAT3 PIN_CFG(225, ALT_B) +#define GPIO225_SPI0_RXD PIN_CFG(225, ALT_C) + +#define GPIO226_GPIO PIN_CFG(226, GPIO) +#define GPIO226_HSIT_ACWAKE0 PIN_CFG(226, ALT_A) +#define GPIO226_PWL PIN_CFG(226, ALT_B) +#define GPIO226_USBSIM_PDC PIN_CFG(226, ALT_C) + +#define GPIO227_GPIO PIN_CFG(227, GPIO) +#define GPIO227_CLKOUT1 PIN_CFG(227, ALT_A) + +#define GPIO228_GPIO PIN_CFG(228, GPIO) +#define GPIO228_CLKOUT2 PIN_CFG(228, ALT_A) + +#define GPIO229_GPIO PIN_CFG(229, GPIO) +#define GPIO229_CLKOUT1 PIN_CFG(229, ALT_A) +#define GPIO229_PWL PIN_CFG(229, ALT_B) +#define GPIO229_I2C3_SDA PIN_CFG(229, ALT_C) + +#define GPIO230_GPIO PIN_CFG(230, GPIO) +#define GPIO230_CLKOUT2 PIN_CFG(230, ALT_A) +#define GPIO230_PWL PIN_CFG(230, ALT_B) +#define GPIO230_I2C3_SCL PIN_CFG(230, ALT_C) + +#define GPIO256_GPIO PIN_CFG(256, GPIO) +#define GPIO256_USB_NXT PIN_CFG(256, ALT_A) + +#define GPIO257_GPIO PIN_CFG(257, GPIO) +#define GPIO257_USB_STP PIN_CFG(257, ALT_A) + +#define GPIO258_GPIO PIN_CFG(258, GPIO) +#define GPIO258_USB_XCLK PIN_CFG(258, ALT_A) +#define GPIO258_NONE PIN_CFG(258, ALT_B) +#define GPIO258_DDR_TRIG PIN_CFG(258, ALT_C) + +#define GPIO259_GPIO PIN_CFG(259, GPIO) +#define GPIO259_USB_DIR PIN_CFG(259, ALT_A) + +#define GPIO260_GPIO PIN_CFG(260, GPIO) +#define GPIO260_USB_DAT7 PIN_CFG(260, ALT_A) + +#define GPIO261_GPIO PIN_CFG(261, GPIO) +#define GPIO261_USB_DAT6 PIN_CFG(261, ALT_A) + +#define GPIO262_GPIO PIN_CFG(262, GPIO) +#define GPIO262_USB_DAT5 PIN_CFG(262, ALT_A) + +#define GPIO263_GPIO PIN_CFG(263, GPIO) +#define GPIO263_USB_DAT4 PIN_CFG(263, ALT_A) + +#define GPIO264_GPIO PIN_CFG(264, GPIO) +#define GPIO264_USB_DAT3 PIN_CFG(264, ALT_A) + +#define GPIO265_GPIO PIN_CFG(265, GPIO) +#define GPIO265_USB_DAT2 PIN_CFG(265, ALT_A) + +#define GPIO266_GPIO PIN_CFG(266, GPIO) +#define GPIO266_USB_DAT1 PIN_CFG(266, ALT_A) + +#define GPIO267_GPIO PIN_CFG(267, GPIO) +#define GPIO267_USB_DAT0 PIN_CFG(267, ALT_A) + +#endif diff --git a/arch/arm/mach-ux500/pins.c b/arch/arm/mach-ux500/pins.c new file mode 100644 index 00000000000..38c1d47b29a --- /dev/null +++ b/arch/arm/mach-ux500/pins.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <plat/pincfg.h> + +#include "pins.h" + +static LIST_HEAD(pin_lookups); +static DEFINE_MUTEX(pin_lookups_mutex); +static DEFINE_SPINLOCK(pins_lock); + +void __init ux500_pins_add(struct ux500_pin_lookup *pl, size_t num) +{ + mutex_lock(&pin_lookups_mutex); + + while (num--) { + list_add_tail(&pl->node, &pin_lookups); + pl++; + } + + mutex_unlock(&pin_lookups_mutex); +} + +struct ux500_pins *ux500_pins_get(const char *name) +{ + struct ux500_pins *pins = NULL; + struct ux500_pin_lookup *pl; + + mutex_lock(&pin_lookups_mutex); + + list_for_each_entry(pl, &pin_lookups, node) { + if (!strcmp(pl->name, name)) { + pins = pl->pins; + goto out; + } + } + +out: + mutex_unlock(&pin_lookups_mutex); + return pins; +} + +int ux500_pins_enable(struct ux500_pins *pins) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&pins_lock, flags); + + if (pins->usage++ == 0) + ret = nmk_config_pins(pins->cfg, pins->num); + + spin_unlock_irqrestore(&pins_lock, flags); + return ret; +} + +int ux500_pins_disable(struct ux500_pins *pins) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&pins_lock, flags); + + if (WARN_ON(pins->usage == 0)) + goto out; + + if (--pins->usage == 0) + ret = nmk_config_pins_sleep(pins->cfg, pins->num); + +out: + spin_unlock_irqrestore(&pins_lock, flags); + return ret; +} + +void ux500_pins_put(struct ux500_pins *pins) +{ + WARN_ON(!pins); +} diff --git a/arch/arm/mach-ux500/pins.h b/arch/arm/mach-ux500/pins.h new file mode 100644 index 00000000000..52e123963f1 --- /dev/null +++ b/arch/arm/mach-ux500/pins.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef __MACH_UX500_PINS_H +#define __MACH_UX500_PINS_H + +#include <linux/list.h> + +#define PIN_LOOKUP(_name, _pins) \ +{ \ + .name = _name, \ + .pins = _pins, \ +} + +#define UX500_PINS(name, pins...) \ +struct ux500_pins name = { \ + .cfg = (pin_cfg_t[]) {pins}, \ + .num = ARRAY_SIZE(((pin_cfg_t[]) {pins})), \ +} + +struct ux500_pins { + int usage; + int num; + pin_cfg_t *cfg; +}; + +struct ux500_pin_lookup { + struct list_head node; + const char *name; + struct ux500_pins *pins; +}; + +void __init ux500_pins_add(struct ux500_pin_lookup *pl, size_t num); +struct ux500_pins *ux500_pins_get(const char *name); +int ux500_pins_enable(struct ux500_pins *pins); +int ux500_pins_disable(struct ux500_pins *pins); +void ux500_pins_put(struct ux500_pins *pins); + +#endif diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 438ef16aec9..47bafde8611 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -21,16 +21,34 @@ #include <asm/localtimer.h> #include <asm/smp_scu.h> #include <mach/hardware.h> +#include <mach/setup.h> /* * control for which core is the next to come out of the secondary * boot "holding pen" */ -volatile int __cpuinitdata pen_release = -1; +volatile int pen_release = -1; + +static void __iomem *scu_base_addr(void) +{ + if (cpu_is_u5500()) + return __io_address(U5500_SCU_BASE); + else if (cpu_is_u8500()) + return __io_address(U8500_SCU_BASE); + else + ux500_unknown_soc(); + + return NULL; +} static unsigned int __init get_core_count(void) { - return scu_get_core_count(__io_address(UX500_SCU_BASE)); + void __iomem *scu_base = scu_base_addr(); + + if (scu_base) + return scu_get_core_count(scu_base); + + return 1; } static DEFINE_SPINLOCK(boot_lock); @@ -44,7 +62,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + gic_cpu_init(0, gic_cpu_base_addr); /* * let the primary processor know we're out of the @@ -78,6 +96,8 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); + smp_cross_call(cpumask_of(cpu)); + timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { if (pen_release == -1) @@ -95,6 +115,15 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) static void __init wakeup_secondary(void) { + void __iomem *backupram; + + if (cpu_is_u5500()) + backupram = __io_address(U5500_BACKUPRAM0_BASE); + else if (cpu_is_u8500()) + backupram = __io_address(U8500_BACKUPRAM0_BASE); + else + ux500_unknown_soc(); + /* nobody is to be released from the pen yet */ pen_release = -1; @@ -104,15 +133,13 @@ static void __init wakeup_secondary(void) * backup ram register at offset 0x1FF0, which is what boot rom code * is waiting for. This would wake up the secondary core from WFE */ -#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4 +#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 __raw_writel(virt_to_phys(u8500_secondary_startup), - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_JUMPADDR_OFFSET); + backupram + UX500_CPU1_JUMPADDR_OFFSET); -#define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 +#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 __raw_writel(0xA1FEED01, - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_WAKEMAGIC_OFFSET); + backupram + UX500_CPU1_WAKEMAGIC_OFFSET); /* make sure write buffer is drained */ mb(); @@ -166,13 +193,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); + percpu_timer_setup(); + if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - scu_enable(__io_address(UX500_SCU_BASE)); + scu_enable(scu_base_addr()); wakeup_secondary(); } } diff --git a/arch/arm/mach-ux500/pm/Kconfig b/arch/arm/mach-ux500/pm/Kconfig new file mode 100644 index 00000000000..5de1afe1bee --- /dev/null +++ b/arch/arm/mach-ux500/pm/Kconfig @@ -0,0 +1,82 @@ +config U8500_CPUFREQ + tristate "CPUFreq support" + depends on UX500_SOC_DB8500 && CPU_FREQ + default y + help + Add support for CPU Frequency scaling for U8500. + +config U8500_CPUIDLE + tristate "CPUIdle support" + depends on UX500_SOC_DB8500 && CPU_IDLE && U8500_PRCMU + default y + select GENERIC_CLOCKEVENTS_BROADCAST + select UX500_CONTEXT + help + Add support for CPUIdle for U8500. + +config U8500_CPUIDLE_DEEPEST_STATE + int "Deepest sleep state" + default 4 + depends on U8500_CPUIDLE + help + Set deepest sleep state. See the cstate struct in cpuidle.c. + Default is ApSleep. + +config U8500_CPUIDLE_DEBUG + bool "CPUIdle debug" + depends on U8500_CPUIDLE && DEBUG_FS + help + Add debugging support for CPUIdle for U8500. + +config UX500_SUSPEND + bool "Suspend to mem and standby support" + depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && PM + select UX500_CONTEXT + help + Add support for suspend. + +config UX500_SUSPEND_STANDBY + bool "Suspend Standby goes to ApSleep" + depends on UX500_SUSPEND && UX500_SOC_DB8500 + help + If yes, echo standby > /sys/power/state puts the system into ApSleep. + +config UX500_SUSPEND_MEM + bool "Suspend Mem goes to ApDeepSleep" + depends on UX500_SUSPEND && UX500_SOC_DB8500 + help + If yes, echo mem > /sys/power/state puts the system into ApDeepSleep else + it will do the same as echo standby > /sys/power/state. + +config UX500_SUSPEND_DBG + bool "Suspend debug" + depends on UX500_SUSPEND && DEBUG_FS + help + Add debug support for suspend. + +config UX500_SUSPEND_DBG_WAKE_ON_UART + bool "Suspend wakes on console UART" + depends on UX500_SUSPEND_DBG + help + Wake up on uart interrupts. Makes it possible for the console to wake up system. + +config UX500_CONSOLE_UART_GPIO_PIN + int "The pin number of the console UART GPIO pin" + default 29 + depends on UX500_SUSPEND_DBG_WAKE_ON_UART || U8500_CPUIDLE_DEBUG + help + GPIO pin number of the GPIO pin connected to the console UART RX line. + +config UX500_CONTEXT + bool "Context save/restore support for UX500" + depends on UX500_SOC_DB8500 || UX500_SOC_DB5500 + help + This is needed for ApSleep and deeper sleep states. + +config UX500_USECASE_GOVERNOR + bool "UX500 use-case governor" + depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && \ + (CPU_FREQ && CPU_IDLE && HOTPLUG_CPU) + default y + help + Adjusts CPU_IDLE, CPU_FREQ, HOTPLUG_CPU and L2 cache parameters diff --git a/arch/arm/mach-ux500/pm/Makefile b/arch/arm/mach-ux500/pm/Makefile new file mode 100644 index 00000000000..abd08ee341e --- /dev/null +++ b/arch/arm/mach-ux500/pm/Makefile @@ -0,0 +1,16 @@ +# +# Power save related files +# +obj-y := pm.o runtime.o + +obj-$(CONFIG_U8500_CPUIDLE) += cpuidle.o +obj-$(CONFIG_U8500_CPUIDLE_DEBUG) += cpuidle_dbg.o +obj-$(CONFIG_UX500_CONTEXT) += context.o context_arm.o context-db8500.o context-db5500.o +obj-$(CONFIG_U8500_CPUFREQ) += cpufreq.o +obj-$(CONFIG_UX500_SUSPEND) += suspend.o +obj-$(CONFIG_UX500_SUSPEND_DBG) += suspend_dbg.o +obj-$(CONFIG_UX500_USECASE_GOVERNOR) += usecase_gov.o + +ifeq ($(CONFIG_UX500_SOC_DB8500), y) +obj-$(CONFIG_U8500_CPUFREQ) += cpufreq-db8500.o +endif diff --git a/arch/arm/mach-ux500/pm/context-db5500.c b/arch/arm/mach-ux500/pm/context-db5500.c new file mode 100644 index 00000000000..f9a8376620f --- /dev/null +++ b/arch/arm/mach-ux500/pm/context-db5500.c @@ -0,0 +1,395 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>, + * Rickard Andersson <rickard.andersson@stericsson.com>, + * Sundar Iyer <sundar.iyer@stericsson.com>, + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#include <linux/io.h> + +#include <mach/hardware.h> + +#include "context.h" + +/* These registers are DB5500 specific */ +#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x0 +#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x4 + +#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x18 +#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x1C +#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x20 + +#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x24 +#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x28 +#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x2C + +#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400 +#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404 +#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408 + +#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424 +#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428 +#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C + +#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430 + +#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800 +#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804 + +#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818 +#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C +#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820 + +#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824 +#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828 +#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C + +#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00 +#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04 +#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08 + +#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC24 +#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC28 +#define NODE_HIBW2_DDR_IN_2_LIMIT 0xC2C + +#define NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC30 + +#define NODE_ESRAM0_IN_0_PRIORITY 0x1000 +#define NODE_ESRAM0_IN_1_PRIORITY 0x1004 +#define NODE_ESRAM0_IN_2_PRIORITY 0x1008 + +#define NODE_ESRAM0_IN_0_LIMIT 0x1024 +#define NODE_ESRAM0_IN_1_LIMIT 0x1028 +#define NODE_ESRAM0_IN_2_LIMIT 0x102C +#define NODE_ESRAM0_OUT_0_PRIORITY 0x1030 + +#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400 +#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404 +#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408 + +#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1424 +#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1428 +#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x142C +#define NODE_ESRAM1_2_OUT_0_PRIORITY 0x1430 + +#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800 +#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804 +#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808 + +#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1824 +#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1828 +#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x182C +#define NODE_ESRAM3_4_OUT_0_PRIORITY 0x1830 + +/* + * Save ICN (Interconnect or Interconnect nodes) configuration registers + * TODO: This can be optimized, for example if we have + * a static ICN configuration. + */ + +static struct { + void __iomem *base; + u32 hibw1_esram_in_pri[2]; + u32 hibw1_esram_in0_arb[3]; + u32 hibw1_esram_in1_arb[3]; + u32 hibw1_ddr_in_prio[3]; + u32 hibw1_ddr_in_limit[3]; + u32 hibw1_ddr_out_prio_reg; + + /* HiBw2 node registers */ + u32 hibw2_esram_in_pri[2]; + u32 hibw2_esram_in0_arblimit[3]; + u32 hibw2_esram_in1_arblimit[3]; + u32 hibw2_ddr_in_prio[3]; + u32 hibw2_ddr_in_limit[3]; + u32 hibw2_ddr_out_prio_reg; + + /* ESRAM node registers */ + u32 esram_in_prio[3]; + u32 esram_in_lim[3]; + u32 esram_out_prio_reg; + + u32 esram12_in_prio[3]; + u32 esram12_in_arb_lim[3]; + u32 esram12_out_prio_reg; + + u32 esram34_in_prio[3]; + u32 esram34_in_arb_lim[3]; + u32 esram34_out_prio; +} context_icn; + + +void u5500_context_save_icn(void) +{ + /* hibw1 */ + context_icn.hibw1_esram_in_pri[0] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); + context_icn.hibw1_esram_in_pri[1] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); + + context_icn.hibw1_esram_in0_arb[0] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); + context_icn.hibw1_esram_in0_arb[1] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); + context_icn.hibw1_esram_in0_arb[2] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); + + context_icn.hibw1_esram_in1_arb[0] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); + context_icn.hibw1_esram_in1_arb[1] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); + context_icn.hibw1_esram_in1_arb[2] = + readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); + + context_icn.hibw1_ddr_in_prio[0] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); + context_icn.hibw1_ddr_in_prio[1] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); + context_icn.hibw1_ddr_in_prio[2] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); + + context_icn.hibw1_ddr_in_limit[0] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); + context_icn.hibw1_ddr_in_limit[1] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); + context_icn.hibw1_ddr_in_limit[2] = + readl(context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); + + context_icn.hibw1_ddr_out_prio_reg = + readl(context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); + + /* hibw2 */ + context_icn.hibw2_esram_in_pri[0] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); + context_icn.hibw2_esram_in_pri[1] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); + + context_icn.hibw2_esram_in0_arblimit[0] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); + context_icn.hibw2_esram_in0_arblimit[1] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); + context_icn.hibw2_esram_in0_arblimit[2] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); + + context_icn.hibw2_esram_in1_arblimit[0] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); + context_icn.hibw2_esram_in1_arblimit[1] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); + context_icn.hibw2_esram_in1_arblimit[2] = + readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); + + context_icn.hibw2_ddr_in_prio[0] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); + context_icn.hibw2_ddr_in_prio[1] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); + context_icn.hibw2_ddr_in_prio[2] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); + + context_icn.hibw2_ddr_in_limit[0] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); + context_icn.hibw2_ddr_in_limit[1] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); + context_icn.hibw2_ddr_in_limit[2] = + readl(context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); + + context_icn.hibw2_ddr_out_prio_reg = + readl(context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY); + + /* ESRAM0 */ + context_icn.esram_in_prio[0] = + readl(context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); + context_icn.esram_in_prio[1] = + readl(context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); + context_icn.esram_in_prio[2] = + readl(context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); + + context_icn.esram_in_lim[0] = + readl(context_icn.base + NODE_ESRAM0_IN_0_LIMIT); + context_icn.esram_in_lim[1] = + readl(context_icn.base + NODE_ESRAM0_IN_1_LIMIT); + context_icn.esram_in_lim[2] = + readl(context_icn.base + NODE_ESRAM0_IN_2_LIMIT); + + context_icn.esram_out_prio_reg = + readl(context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY); + + /* ESRAM1-2 */ + context_icn.esram12_in_prio[0] = + readl(context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); + context_icn.esram12_in_prio[1] = + readl(context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); + context_icn.esram12_in_prio[2] = + readl(context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); + + context_icn.esram12_in_arb_lim[0] = + readl(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[1] = + readl(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[2] = + readl(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); + + context_icn.esram12_out_prio_reg = + readl(context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY); + + /* ESRAM3-4 */ + context_icn.esram34_in_prio[0] = + readl(context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); + context_icn.esram34_in_prio[1] = + readl(context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); + context_icn.esram34_in_prio[2] = + readl(context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); + + context_icn.esram34_in_arb_lim[0] = + readl(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[1] = + readl(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[2] = + readl(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); + + context_icn.esram34_out_prio = + readl(context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY); +} + +/* + * Restore ICN configuration registers + */ +void u5500_context_restore_icn(void) +{ + + /* hibw1 */ + writel(context_icn.hibw1_esram_in_pri[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); + writel(context_icn.hibw1_esram_in_pri[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); + + writel(context_icn.hibw1_esram_in0_arb[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); + writel(context_icn.hibw1_esram_in0_arb[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); + writel(context_icn.hibw1_esram_in0_arb[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); + + writel(context_icn.hibw1_esram_in1_arb[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); + writel(context_icn.hibw1_esram_in1_arb[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); + writel(context_icn.hibw1_esram_in1_arb[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); + + writel(context_icn.hibw1_ddr_in_prio[0], + context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); + writel(context_icn.hibw1_ddr_in_prio[1], + context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); + writel(context_icn.hibw1_ddr_in_prio[2], + context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); + + writel(context_icn.hibw1_ddr_in_limit[0], + context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); + writel(context_icn.hibw1_ddr_in_limit[1], + context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); + writel(context_icn.hibw1_ddr_in_limit[2], + context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); + + writel(context_icn.hibw1_ddr_out_prio_reg, + context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); + + /* hibw2 */ + writel(context_icn.hibw2_esram_in_pri[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); + writel(context_icn.hibw2_esram_in_pri[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); + + writel(context_icn.hibw2_esram_in0_arblimit[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); + writel(context_icn.hibw2_esram_in0_arblimit[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); + writel(context_icn.hibw2_esram_in0_arblimit[2], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); + + writel(context_icn.hibw2_esram_in1_arblimit[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); + writel(context_icn.hibw2_esram_in1_arblimit[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); + writel(context_icn.hibw2_esram_in1_arblimit[2], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); + + writel(context_icn.hibw2_ddr_in_prio[0], + context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); + writel(context_icn.hibw2_ddr_in_prio[1], + context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); + writel(context_icn.hibw2_ddr_in_prio[2], + context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); + + writel(context_icn.hibw2_ddr_in_limit[0], + context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); + writel(context_icn.hibw2_ddr_in_limit[1], + context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); + writel(context_icn.hibw2_ddr_in_limit[2], + context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); + + writel(context_icn.hibw2_ddr_out_prio_reg, + context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY); + + /* ESRAM0 */ + writel(context_icn.esram_in_prio[0], + context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); + writel(context_icn.esram_in_prio[1], + context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); + writel(context_icn.esram_in_prio[2], + context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); + + writel(context_icn.esram_in_lim[0], + context_icn.base + NODE_ESRAM0_IN_0_LIMIT); + writel(context_icn.esram_in_lim[1], + context_icn.base + NODE_ESRAM0_IN_1_LIMIT); + writel(context_icn.esram_in_lim[2], + context_icn.base + NODE_ESRAM0_IN_2_LIMIT); + + writel(context_icn.esram_out_prio_reg, + context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY); + + /* ESRAM1-2 */ + writel(context_icn.esram12_in_prio[0], + context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); + writel(context_icn.esram12_in_prio[1], + context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); + writel(context_icn.esram12_in_prio[2], + context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); + + writel(context_icn.esram12_in_arb_lim[0], + context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[1], + context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[2], + context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); + + writel(context_icn.esram12_out_prio_reg, + context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY); + + /* ESRAM3-4 */ + writel(context_icn.esram34_in_prio[0], + context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); + writel(context_icn.esram34_in_prio[1], + context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); + writel(context_icn.esram34_in_prio[2], + context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); + + writel(context_icn.esram34_in_arb_lim[0], + context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[1], + context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[2], + context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); + + writel(context_icn.esram34_out_prio, + context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY); + +} + +void u5500_context_init(void) +{ + context_icn.base = ioremap(U5500_ICN_BASE, SZ_4K); +} diff --git a/arch/arm/mach-ux500/pm/context-db8500.c b/arch/arm/mach-ux500/pm/context-db8500.c new file mode 100644 index 00000000000..f43a2a81f8e --- /dev/null +++ b/arch/arm/mach-ux500/pm/context-db8500.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * + */ + +#include <linux/io.h> + +#include <mach/hardware.h> + +#include "context.h" + +/* + * ST-Interconnect context + */ + +/* priority, bw limiter register offsets */ +#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x00 +#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x04 +#define NODE_HIBW1_ESRAM_IN_2_PRIORITY 0x08 +#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x24 +#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x28 +#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x2C +#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x30 +#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x34 +#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x38 +#define NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT 0x3C +#define NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT 0x40 +#define NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT 0x44 +#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400 +#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404 +#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408 +#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424 +#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428 +#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C +#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430 +#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800 +#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804 +#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818 +#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C +#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820 +#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824 +#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828 +#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C +#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00 +#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04 +#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08 +/* only in v1 */ +#define NODE_HIBW2_DDR_IN_3_PRIORITY 0xC0C +/* address update between v1 and v2 */ +#define NODE_HIBW2_DDR_IN_0_LIMIT_V1 0xC30 +#define NODE_HIBW2_DDR_IN_1_LIMIT_V1 0xC34 +#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC24 +#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC28 +/* only in v2 */ +#define NODE_HIBW2_DDR_IN_2_LIMIT 0xC2C +#define NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC30 +#define NODE_ESRAM0_IN_0_PRIORITY 0X1000 +#define NODE_ESRAM0_IN_1_PRIORITY 0X1004 +#define NODE_ESRAM0_IN_2_PRIORITY 0X1008 +#define NODE_ESRAM0_IN_3_PRIORITY 0X100C +#define NODE_ESRAM0_IN_0_LIMIT 0X1030 +#define NODE_ESRAM0_IN_1_LIMIT 0X1034 +#define NODE_ESRAM0_IN_2_LIMIT 0X1038 +#define NODE_ESRAM0_IN_3_LIMIT 0X103C +/* common */ +#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400 +#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404 +#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408 +#define NODE_ESRAM1_2_IN_3_PRIORITY 0x140C +#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1430 +#define NODE_ESRAM1_2_IN_0_ARB_2_LIMIT 0x1434 +#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1438 +#define NODE_ESRAM1_2_IN_1_ARB_2_LIMIT 0x143C +#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x1440 +#define NODE_ESRAM1_2_IN_2_ARB_2_LIMIT 0x1444 +#define NODE_ESRAM1_2_IN_3_ARB_1_LIMIT 0x1448 +#define NODE_ESRAM1_2_IN_3_ARB_2_LIMIT 0x144C +#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800 +#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804 +#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808 +#define NODE_ESRAM3_4_IN_3_PRIORITY 0x180C +#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1830 +#define NODE_ESRAM3_4_IN_0_ARB_2_LIMIT 0x1834 +#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1838 +#define NODE_ESRAM3_4_IN_1_ARB_2_LIMIT 0x183C +#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x1840 +#define NODE_ESRAM3_4_IN_2_ARB_2_LIMIT 0x1844 +#define NODE_ESRAM3_4_IN_3_ARB_1_LIMIT 0x1848 +#define NODE_ESRAM3_4_IN_3_ARB_2_LIMIT 0x184C + +static struct { + void __iomem *base; + u32 hibw1_esram_in_pri[3]; + u32 hibw1_esram_in0_arb[3]; + u32 hibw1_esram_in1_arb[3]; + u32 hibw1_esram_in2_arb[3]; + u32 hibw1_ddr_in_prio[3]; + u32 hibw1_ddr_in_limit[3]; + u32 hibw1_ddr_out_prio; + + /* HiBw2 node registers */ + u32 hibw2_esram_in_pri[2]; + u32 hibw2_esram_in0_arblimit[3]; + u32 hibw2_esram_in1_arblimit[3]; + u32 hibw2_ddr_in_prio[4]; + u32 hibw2_ddr_in_limit[4]; + u32 hibw2_ddr_out_prio; + + /* ESRAM node registers */ + u32 esram_in_prio[4]; + u32 esram_in_lim[4]; + u32 esram0_in_prio[4]; + u32 esram0_in_lim[4]; + u32 esram12_in_prio[4]; + u32 esram12_in_arb_lim[8]; + u32 esram34_in_prio[4]; + u32 esram34_in_arb_lim[8]; +} context_icn; + +/** + * u8500_context_save_icn() - save ICN context + * + */ +void u8500_context_save_icn(void) +{ + + context_icn.hibw1_esram_in_pri[0] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); + context_icn.hibw1_esram_in_pri[1] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); + context_icn.hibw1_esram_in_pri[2] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_PRIORITY); + + context_icn.hibw1_esram_in0_arb[0] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); + context_icn.hibw1_esram_in0_arb[1] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); + context_icn.hibw1_esram_in0_arb[2] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); + + context_icn.hibw1_esram_in1_arb[0] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); + context_icn.hibw1_esram_in1_arb[1] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); + context_icn.hibw1_esram_in1_arb[2] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); + + context_icn.hibw1_esram_in2_arb[0] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT); + context_icn.hibw1_esram_in2_arb[1] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT); + context_icn.hibw1_esram_in2_arb[2] = + readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT); + + context_icn.hibw1_ddr_in_prio[0] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); + context_icn.hibw1_ddr_in_prio[1] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); + context_icn.hibw1_ddr_in_prio[2] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); + + context_icn.hibw1_ddr_in_limit[0] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); + context_icn.hibw1_ddr_in_limit[1] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); + context_icn.hibw1_ddr_in_limit[2] = + readb(context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); + + context_icn.hibw1_ddr_out_prio = + readb(context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); + + context_icn.hibw2_esram_in_pri[0] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); + context_icn.hibw2_esram_in_pri[1] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); + + context_icn.hibw2_esram_in0_arblimit[0] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); + context_icn.hibw2_esram_in0_arblimit[1] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); + context_icn.hibw2_esram_in0_arblimit[2] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); + + context_icn.hibw2_esram_in1_arblimit[0] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); + context_icn.hibw2_esram_in1_arblimit[1] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); + context_icn.hibw2_esram_in1_arblimit[2] = + readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); + + context_icn.hibw2_ddr_in_prio[0] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); + context_icn.hibw2_ddr_in_prio[1] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); + context_icn.hibw2_ddr_in_prio[2] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); + + if (cpu_is_u8500v1()) { + context_icn.hibw2_ddr_in_prio[3] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY); + + context_icn.hibw2_ddr_in_limit[0] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT_V1); + context_icn.hibw2_ddr_in_limit[1] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT_V1); + } + + if (cpu_is_u8500v2()) { + context_icn.hibw2_ddr_in_limit[0] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); + context_icn.hibw2_ddr_in_limit[1] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); + + context_icn.hibw2_ddr_in_limit[2] = + readb(context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); + + context_icn.hibw2_ddr_out_prio = + readb(context_icn.base + + NODE_HIBW2_DDR_OUT_0_PRIORITY); + + context_icn.esram0_in_prio[0] = + readb(context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); + context_icn.esram0_in_prio[1] = + readb(context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); + context_icn.esram0_in_prio[2] = + readb(context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); + context_icn.esram0_in_prio[3] = + readb(context_icn.base + NODE_ESRAM0_IN_3_PRIORITY); + + context_icn.esram0_in_lim[0] = + readb(context_icn.base + NODE_ESRAM0_IN_0_LIMIT); + context_icn.esram0_in_lim[1] = + readb(context_icn.base + NODE_ESRAM0_IN_1_LIMIT); + context_icn.esram0_in_lim[2] = + readb(context_icn.base + NODE_ESRAM0_IN_2_LIMIT); + context_icn.esram0_in_lim[3] = + readb(context_icn.base + NODE_ESRAM0_IN_3_LIMIT); + } + context_icn.esram12_in_prio[0] = + readb(context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); + context_icn.esram12_in_prio[1] = + readb(context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); + context_icn.esram12_in_prio[2] = + readb(context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); + context_icn.esram12_in_prio[3] = + readb(context_icn.base + NODE_ESRAM1_2_IN_3_PRIORITY); + + context_icn.esram12_in_arb_lim[0] = + readb(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[1] = + readb(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT); + context_icn.esram12_in_arb_lim[2] = + readb(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[3] = + readb(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT); + context_icn.esram12_in_arb_lim[4] = + readb(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[5] = + readb(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT); + context_icn.esram12_in_arb_lim[6] = + readb(context_icn.base + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT); + context_icn.esram12_in_arb_lim[7] = + readb(context_icn.base + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT); + + context_icn.esram34_in_prio[0] = + readb(context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); + context_icn.esram34_in_prio[1] = + readb(context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); + context_icn.esram34_in_prio[2] = + readb(context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); + context_icn.esram34_in_prio[3] = + readb(context_icn.base + NODE_ESRAM3_4_IN_3_PRIORITY); + + context_icn.esram34_in_arb_lim[0] = + readb(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[1] = + readb(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT); + context_icn.esram34_in_arb_lim[2] = + readb(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[3] = + readb(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT); + context_icn.esram34_in_arb_lim[4] = + readb(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[5] = + readb(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT); + context_icn.esram34_in_arb_lim[6] = + readb(context_icn.base + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT); + context_icn.esram34_in_arb_lim[7] = + readb(context_icn.base + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT); + +} + +/** + * u8500_context_restore_icn() - restore ICN context + * + */ +void u8500_context_restore_icn(void) +{ + writel(context_icn.hibw1_esram_in_pri[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); + writel(context_icn.hibw1_esram_in_pri[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); + writel(context_icn.hibw1_esram_in_pri[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_2_PRIORITY); + + writel(context_icn.hibw1_esram_in0_arb[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); + writel(context_icn.hibw1_esram_in0_arb[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); + writel(context_icn.hibw1_esram_in0_arb[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); + + writel(context_icn.hibw1_esram_in1_arb[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); + writel(context_icn.hibw1_esram_in1_arb[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); + writel(context_icn.hibw1_esram_in1_arb[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); + + writel(context_icn.hibw1_esram_in2_arb[0], + context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT); + writel(context_icn.hibw1_esram_in2_arb[1], + context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT); + writel(context_icn.hibw1_esram_in2_arb[2], + context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT); + + writel(context_icn.hibw1_ddr_in_prio[0], + context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); + writel(context_icn.hibw1_ddr_in_prio[1], + context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); + writel(context_icn.hibw1_ddr_in_prio[2], + context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); + + writel(context_icn.hibw1_ddr_in_limit[0], + context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); + writel(context_icn.hibw1_ddr_in_limit[1], + context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); + writel(context_icn.hibw1_ddr_in_limit[2], + context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); + + writel(context_icn.hibw1_ddr_out_prio, + context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); + + writel(context_icn.hibw2_esram_in_pri[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); + writel(context_icn.hibw2_esram_in_pri[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); + + writel(context_icn.hibw2_esram_in0_arblimit[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); + writel(context_icn.hibw2_esram_in0_arblimit[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); + writel(context_icn.hibw2_esram_in0_arblimit[2], + context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); + + writel(context_icn.hibw2_esram_in1_arblimit[0], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); + writel(context_icn.hibw2_esram_in1_arblimit[1], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); + writel(context_icn.hibw2_esram_in1_arblimit[2], + context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); + + writel(context_icn.hibw2_ddr_in_prio[0], + context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); + writel(context_icn.hibw2_ddr_in_prio[1], + context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); + writel(context_icn.hibw2_ddr_in_prio[2], + context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); + if (cpu_is_u8500v1()) { + writel(context_icn.hibw2_ddr_in_prio[3], + context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY); + writel(context_icn.hibw2_ddr_in_limit[0], + context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT_V1); + writel(context_icn.hibw2_ddr_in_limit[1], + context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT_V1); + } + if (cpu_is_u8500v2()) { + writel(context_icn.hibw2_ddr_in_limit[0], + context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); + writel(context_icn.hibw2_ddr_in_limit[1], + context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); + writel(context_icn.hibw2_ddr_in_limit[2], + context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); + writel(context_icn.hibw2_ddr_out_prio, + context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY); + + writel(context_icn.esram0_in_prio[0], + context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); + writel(context_icn.esram0_in_prio[1], + context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); + writel(context_icn.esram0_in_prio[2], + context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); + writel(context_icn.esram0_in_prio[3], + context_icn.base + NODE_ESRAM0_IN_3_PRIORITY); + + writel(context_icn.esram0_in_lim[0], + context_icn.base + NODE_ESRAM0_IN_0_LIMIT); + writel(context_icn.esram0_in_lim[1], + context_icn.base + NODE_ESRAM0_IN_1_LIMIT); + writel(context_icn.esram0_in_lim[2], + context_icn.base + NODE_ESRAM0_IN_2_LIMIT); + writel(context_icn.esram0_in_lim[3], + context_icn.base + NODE_ESRAM0_IN_3_LIMIT); + } + + writel(context_icn.esram12_in_prio[0], + context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); + writel(context_icn.esram12_in_prio[1], + context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); + writel(context_icn.esram12_in_prio[2], + context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); + writel(context_icn.esram12_in_prio[3], + context_icn.base + NODE_ESRAM1_2_IN_3_PRIORITY); + + writel(context_icn.esram12_in_arb_lim[0], + context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[1], + context_icn.base + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT); + writel(context_icn.esram12_in_arb_lim[2], + context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[3], + context_icn.base + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT); + writel(context_icn.esram12_in_arb_lim[4], + context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[5], + context_icn.base + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT); + writel(context_icn.esram12_in_arb_lim[6], + context_icn.base + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT); + writel(context_icn.esram12_in_arb_lim[7], + context_icn.base + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT); + + writel(context_icn.esram34_in_prio[0], + context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); + writel(context_icn.esram34_in_prio[1], + context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); + writel(context_icn.esram34_in_prio[2], + context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); + writel(context_icn.esram34_in_prio[3], + context_icn.base + NODE_ESRAM3_4_IN_3_PRIORITY); + + writel(context_icn.esram34_in_arb_lim[0], + context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[1], + context_icn.base + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT); + writel(context_icn.esram34_in_arb_lim[2], + context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[3], + context_icn.base + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT); + writel(context_icn.esram34_in_arb_lim[4], + context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[5], + context_icn.base + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT); + writel(context_icn.esram34_in_arb_lim[6], + context_icn.base + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT); + writel(context_icn.esram34_in_arb_lim[7], + context_icn.base + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT); + +} + +void u8500_context_init(void) +{ + context_icn.base = ioremap(U8500_ICN_BASE, SZ_8K); +} diff --git a/arch/arm/mach-ux500/pm/context.c b/arch/arm/mach-ux500/pm/context.c new file mode 100644 index 00000000000..3bfb3acf8c9 --- /dev/null +++ b/arch/arm/mach-ux500/pm/context.c @@ -0,0 +1,911 @@ +/* + * Copyright (C) ST-Ericsson SA 2010-2011 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>, + * Rickard Andersson <rickard.andersson@stericsson.com>, + * Jonas Aaberg <jonas.aberg@stericsson.com>, + * Sundar Iyer for ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/smp.h> +#include <linux/percpu.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/notifier.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/scu.h> + +#include <plat/gpio.h> + +#include "context.h" +#include "pm.h" + +#define GPIO_NUM_BANKS 9 +#define GPIO_NUM_SAVE_REGISTERS 7 + +/* + * TODO: + * - Use the "UX500*"-macros instead where possible + */ + +#define U8500_BACKUPRAM_SIZE SZ_64K + +#define U8500_PUBLIC_BOOT_ROM_BASE (U8500_BOOT_ROM_BASE + 0x17000) + +/* Special dedicated addresses in backup RAM */ +#define U8500_EXT_RAM_LOC_BACKUPRAM_ADDR 0x80151FDC +#define U8500_CPU0_CP15_CR_BACKUPRAM_ADDR 0x80151F80 +#define U8500_CPU1_CP15_CR_BACKUPRAM_ADDR 0x80151FA0 + +/* For v1.x */ +#define U8500_CPU0_BACKUPRAM_ADDR_BACKUPRAM_LOG_ADDR 0x80151FD8 +#define U8500_CPU1_BACKUPRAM_ADDR_BACKUPRAM_LOG_ADDR 0x80151FE0 + +/* For v2.0 and later */ +#define U8500_CPU0_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR 0x80151FD8 +#define U8500_CPU1_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR 0x80151FE0 + +#define GIC_DIST_ENABLE_NS 0x0 + +/* 32 interrupts fits in 4 bytes */ +#define GIC_DIST_ENABLE_SET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \ + IRQ_SHPI_START) / 32) +#define GIC_DIST_ENABLE_SET_CPU_NUM (IRQ_SHPI_START / 32) +#define GIC_DIST_ENABLE_SET_SPI0 GIC_DIST_ENABLE_SET +#define GIC_DIST_ENABLE_SET_SPI32 (GIC_DIST_ENABLE_SET + IRQ_SHPI_START / 8) + +#define GIC_DIST_PRI_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) / 4) +#define GIC_DIST_PRI_CPU_NUM (IRQ_SHPI_START / 4) +#define GIC_DIST_PRI_SPI0 GIC_DIST_PRI +#define GIC_DIST_PRI_SPI32 (GIC_DIST_PRI + IRQ_SHPI_START) + +#define GIC_DIST_SPI_TARGET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \ + IRQ_SHPI_START) / 4) +#define GIC_DIST_SPI_TARGET_CPU_NUM (IRQ_SHPI_START / 4) +#define GIC_DIST_SPI_TARGET_SPI0 GIC_DIST_TARGET +#define GIC_DIST_SPI_TARGET_SPI32 (GIC_DIST_TARGET + IRQ_SHPI_START) + +/* 16 interrupts per 4 bytes */ +#define GIC_DIST_CONFIG_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) \ + / 16) +#define GIC_DIST_CONFIG_CPU_NUM (IRQ_SHPI_START / 16) +#define GIC_DIST_CONFIG_SPI0 GIC_DIST_CONFIG +#define GIC_DIST_CONFIG_SPI32 (GIC_DIST_CONFIG + IRQ_SHPI_START / 4) + +/* TODO! Move STM reg offsets to suitable place */ +#define STM_CR_OFFSET 0x00 +#define STM_MMC_OFFSET 0x08 +#define STM_TER_OFFSET 0x10 + +#define TPIU_PORT_SIZE 0x4 +#define TPIU_TRIGGER_COUNTER 0x104 +#define TPIU_TRIGGER_MULTIPLIER 0x108 +#define TPIU_CURRENT_TEST_PATTERN 0x204 +#define TPIU_TEST_PATTERN_REPEAT 0x208 +#define TPIU_FORMATTER 0x304 +#define TPIU_FORMATTER_SYNC 0x308 +#define TPIU_LOCK_ACCESS_REGISTER 0xFB0 + +#define TPIU_UNLOCK_CODE 0xc5acce55 + +#define SCU_FILTER_STARTADDR 0x40 +#define SCU_FILTER_ENDADDR 0x44 +#define SCU_ACCESS_CTRL_SAC 0x50 + +/* + * Periph clock cluster context + */ +#define PRCC_BCK_EN 0x00 +#define PRCC_KCK_EN 0x08 +#define PRCC_BCK_STATUS 0x10 +#define PRCC_KCK_STATUS 0x14 + +/* The context of the Trace Port Interface Unit (TPIU) */ +static struct { + void __iomem *base; + u32 port_size; + u32 trigger_counter; + u32 trigger_multiplier; + u32 current_test_pattern; + u32 test_pattern_repeat; + u32 formatter; + u32 formatter_sync; +} context_tpiu; + +static struct { + void __iomem *base; + u32 cr; + u32 mmc; + u32 ter; +} context_stm_ape; + +struct context_gic_cpu { + void __iomem *base; + u32 ctrl; + u32 primask; + u32 binpoint; +}; +static DEFINE_PER_CPU(struct context_gic_cpu, context_gic_cpu); + +static struct { + void __iomem *base; + u32 ns; + u32 enable_set[GIC_DIST_ENABLE_SET_COMMON_NUM]; /* IRQ 32 to 160 */ + u32 priority_level[GIC_DIST_PRI_COMMON_NUM]; + u32 spi_target[GIC_DIST_SPI_TARGET_COMMON_NUM]; + u32 config[GIC_DIST_CONFIG_COMMON_NUM]; +} context_gic_dist_common; + +struct context_gic_dist_cpu { + void __iomem *base; + u32 enable_set[GIC_DIST_ENABLE_SET_CPU_NUM]; /* IRQ 0 to 31 */ + u32 priority_level[GIC_DIST_PRI_CPU_NUM]; + u32 spi_target[GIC_DIST_SPI_TARGET_CPU_NUM]; + u32 config[GIC_DIST_CONFIG_CPU_NUM]; +}; +static DEFINE_PER_CPU(struct context_gic_dist_cpu, context_gic_dist_cpu); + +static struct { + void __iomem *base; + u32 ctrl; + u32 cpu_pwrstatus; + u32 inv_all_nonsecure; + u32 filter_start_addr; + u32 filter_end_addr; + u32 access_ctrl_sac; +} context_scu; + +#define UX500_NR_PRCC_BANKS 5 +static struct { + void __iomem *base; + struct clk *clk; + u32 bus_clk; + u32 kern_clk; +} context_prcc[UX500_NR_PRCC_BANKS]; + +static u32 backup_sram_storage[NR_CPUS] = { + IO_ADDRESS(U8500_CPU0_CP15_CR_BACKUPRAM_ADDR), + IO_ADDRESS(U8500_CPU1_CP15_CR_BACKUPRAM_ADDR), +}; + +static u32 gpio_bankaddr[GPIO_NUM_BANKS] = {IO_ADDRESS(U8500_GPIOBANK0_BASE), + IO_ADDRESS(U8500_GPIOBANK1_BASE), + IO_ADDRESS(U8500_GPIOBANK2_BASE), + IO_ADDRESS(U8500_GPIOBANK3_BASE), + IO_ADDRESS(U8500_GPIOBANK4_BASE), + IO_ADDRESS(U8500_GPIOBANK5_BASE), + IO_ADDRESS(U8500_GPIOBANK6_BASE), + IO_ADDRESS(U8500_GPIOBANK7_BASE), + IO_ADDRESS(U8500_GPIOBANK8_BASE) +}; + +static u32 gpio_save[GPIO_NUM_BANKS][GPIO_NUM_SAVE_REGISTERS]; + +/* + * Stacks and stack pointers + */ +static DEFINE_PER_CPU(u32, varm_registers_backup_stack[1024]); +static DEFINE_PER_CPU(u32 *, varm_registers_pointer); + +static DEFINE_PER_CPU(u32, varm_cp15_backup_stack[1024]); +static DEFINE_PER_CPU(u32 *, varm_cp15_pointer); + + +static ATOMIC_NOTIFIER_HEAD(context_ape_notifier_list); +static ATOMIC_NOTIFIER_HEAD(context_arm_notifier_list); + +/* + * Register a simple callback for handling vape context save/restore + */ +int context_ape_notifier_register(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&context_ape_notifier_list, nb); +} +EXPORT_SYMBOL(context_ape_notifier_register); + +/* + * Remove a previously registered callback + */ +int context_ape_notifier_unregister(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&context_ape_notifier_list, + nb); +} +EXPORT_SYMBOL(context_ape_notifier_unregister); + +/* + * Register a simple callback for handling varm context save/restore + */ +int context_arm_notifier_register(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&context_arm_notifier_list, nb); +} +EXPORT_SYMBOL(context_arm_notifier_register); + +/* + * Remove a previously registered callback + */ +int context_arm_notifier_unregister(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&context_arm_notifier_list, + nb); +} +EXPORT_SYMBOL(context_arm_notifier_unregister); + +static void save_prcc(void) +{ + int i; + + for (i = 0; i < UX500_NR_PRCC_BANKS; i++) { + clk_enable(context_prcc[i].clk); + + context_prcc[i].bus_clk = + readl(context_prcc[i].base + PRCC_BCK_STATUS); + context_prcc[i].kern_clk = + readl(context_prcc[i].base + PRCC_KCK_STATUS); + + clk_disable(context_prcc[i].clk); + } +} + +static void restore_prcc(void) +{ + int i; + + for (i = 0; i < UX500_NR_PRCC_BANKS; i++) { + clk_enable(context_prcc[i].clk); + + writel(context_prcc[i].bus_clk, + context_prcc[i].base + PRCC_BCK_EN); + writel(context_prcc[i].kern_clk, + context_prcc[i].base + PRCC_KCK_EN); + + clk_disable(context_prcc[i].clk); + } +} + +static void save_stm_ape(void) +{ + /* + * TODO: Check with PRCMU developers how STM is handled by PRCMU + * firmware. According to DB5500 design spec there is a "flush" + * mechanism supposed to be used by the PRCMU before power down, + * PRCMU fw might save/restore the following three registers + * at the same time. + */ + context_stm_ape.cr = readl(context_stm_ape.base + + STM_CR_OFFSET); + context_stm_ape.mmc = readl(context_stm_ape.base + + STM_MMC_OFFSET); + context_stm_ape.ter = readl(context_stm_ape.base + + STM_TER_OFFSET); +} + +static void restore_stm_ape(void) +{ + writel(context_stm_ape.ter, + context_stm_ape.base + STM_TER_OFFSET); + writel(context_stm_ape.mmc, + context_stm_ape.base + STM_MMC_OFFSET); + writel(context_stm_ape.cr, + context_stm_ape.base + STM_CR_OFFSET); +} + +/* + * Save the context of the Trace Port Interface Unit (TPIU). + * Saving/restoring is needed for the PTM tracing to work together + * with the sleep states ApSleep and ApDeepSleep. + */ +static void save_tpiu(void) +{ + context_tpiu.port_size = readl(context_tpiu.base + + TPIU_PORT_SIZE); + context_tpiu.trigger_counter = readl(context_tpiu.base + + TPIU_TRIGGER_COUNTER); + context_tpiu.trigger_multiplier = readl(context_tpiu.base + + TPIU_TRIGGER_MULTIPLIER); + context_tpiu.current_test_pattern = readl(context_tpiu.base + + TPIU_CURRENT_TEST_PATTERN); + context_tpiu.test_pattern_repeat = readl(context_tpiu.base + + TPIU_TEST_PATTERN_REPEAT); + context_tpiu.formatter = readl(context_tpiu.base + + TPIU_FORMATTER); + context_tpiu.formatter_sync = readl(context_tpiu.base + + TPIU_FORMATTER_SYNC); +} + +/* + * Restore the context of the Trace Port Interface Unit (TPIU). + * Saving/restoring is needed for the PTM tracing to work together + * with the sleep states ApSleep and ApDeepSleep. + */ +static void restore_tpiu(void) +{ + writel(TPIU_UNLOCK_CODE, + context_tpiu.base + TPIU_LOCK_ACCESS_REGISTER); + + writel(context_tpiu.port_size, + context_tpiu.base + TPIU_PORT_SIZE); + writel(context_tpiu.trigger_counter, + context_tpiu.base + TPIU_TRIGGER_COUNTER); + writel(context_tpiu.trigger_multiplier, + context_tpiu.base + TPIU_TRIGGER_MULTIPLIER); + writel(context_tpiu.current_test_pattern, + context_tpiu.base + TPIU_CURRENT_TEST_PATTERN); + writel(context_tpiu.test_pattern_repeat, + context_tpiu.base + TPIU_TEST_PATTERN_REPEAT); + writel(context_tpiu.formatter, + context_tpiu.base + TPIU_FORMATTER); + writel(context_tpiu.formatter_sync, + context_tpiu.base + TPIU_FORMATTER_SYNC); +} + +/* + * Save GIC CPU IF registers + * + * This is per cpu so it needs to be called for each one. + */ + +static void save_gic_if_cpu(struct context_gic_cpu *c_gic_cpu) +{ + c_gic_cpu->ctrl = readl(c_gic_cpu->base + GIC_CPU_CTRL); + c_gic_cpu->primask = readl(c_gic_cpu->base + GIC_CPU_PRIMASK); + c_gic_cpu->binpoint = readl(c_gic_cpu->base + GIC_CPU_BINPOINT); +} + +/* + * Restore GIC CPU IF registers + * + * This is per cpu so it needs to be called for each one. + */ +static void restore_gic_if_cpu(struct context_gic_cpu *c_gic_cpu) +{ + writel(c_gic_cpu->ctrl, c_gic_cpu->base + GIC_CPU_CTRL); + writel(c_gic_cpu->primask, c_gic_cpu->base + GIC_CPU_PRIMASK); + writel(c_gic_cpu->binpoint, c_gic_cpu->base + GIC_CPU_BINPOINT); +} + +/* + * Save GIC Distributor Common registers + * + * This context is common. Only one CPU needs to call. + * + * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159. + */ + +static void save_gic_dist_common(void) +{ + int i; + + context_gic_dist_common.ns = readl(context_gic_dist_common.base + + GIC_DIST_ENABLE_NS); + + for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++) + context_gic_dist_common.enable_set[i] = + readl(context_gic_dist_common.base + + GIC_DIST_ENABLE_SET_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++) + context_gic_dist_common.priority_level[i] = + readl(context_gic_dist_common.base + + GIC_DIST_PRI_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++) + context_gic_dist_common.spi_target[i] = + readl(context_gic_dist_common.base + + GIC_DIST_SPI_TARGET_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++) + context_gic_dist_common.spi_target[i] = + readl(context_gic_dist_common.base + + GIC_DIST_CONFIG_SPI32 + i * 4); +} + +/* + * Restore GIC Distributor Common registers + * + * This context is common. Only one CPU needs to call. + * + * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159. + */ +static void restore_gic_dist_common(void) +{ + + int i; + + for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++) + writel(context_gic_dist_common.spi_target[i], + context_gic_dist_common.base + + GIC_DIST_CONFIG_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++) + writel(context_gic_dist_common.spi_target[i], + context_gic_dist_common.base + + GIC_DIST_SPI_TARGET_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++) + writel(context_gic_dist_common.priority_level[i], + context_gic_dist_common.base + + GIC_DIST_PRI_SPI32 + i * 4); + + for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++) + writel(context_gic_dist_common.enable_set[i], + context_gic_dist_common.base + + GIC_DIST_ENABLE_SET_SPI32 + i * 4); + + writel(context_gic_dist_common.ns, + context_gic_dist_common.base + GIC_DIST_ENABLE_NS); +} + + + +/* + * Save GIC Dist CPU registers + * + * This needs to be called by all cpu:s which will not call + * save_gic_dist_common(). Only the registers of the GIC which are + * banked will be saved. + */ +static void save_gic_dist_cpu(struct context_gic_dist_cpu *c_gic) +{ + int i; + + for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++) + c_gic->enable_set[i] = + readl(c_gic->base + + GIC_DIST_ENABLE_SET_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++) + c_gic->priority_level[i] = + readl(c_gic->base + + GIC_DIST_PRI_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++) + c_gic->spi_target[i] = + readl(c_gic->base + + GIC_DIST_SPI_TARGET_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++) + c_gic->spi_target[i] = + readl(c_gic->base + + GIC_DIST_CONFIG_SPI0 + i * 4); +} + +/* + * Restore GIC Dist CPU registers + * + * This needs to be called by all cpu:s which will not call + * restore_gic_dist_common(). Only the registers of the GIC which are + * banked will be saved. + */ +static void restore_gic_dist_cpu(struct context_gic_dist_cpu *c_gic) +{ + + int i; + + for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++) + writel(c_gic->spi_target[i], + c_gic->base + + GIC_DIST_CONFIG_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++) + writel(c_gic->spi_target[i], + c_gic->base + + GIC_DIST_SPI_TARGET_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++) + writel(c_gic->priority_level[i], + c_gic->base + + GIC_DIST_PRI_SPI0 + i * 4); + + for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++) + writel(c_gic->enable_set[i], + c_gic->base + + GIC_DIST_ENABLE_SET_SPI0 + i * 4); +} +static void save_scu(void) +{ + context_scu.ctrl = + readl(context_scu.base + SCU_CTRL); + context_scu.cpu_pwrstatus = + readl(context_scu.base + SCU_CPU_STATUS); + context_scu.inv_all_nonsecure = + readl(context_scu.base + SCU_INVALIDATE); + context_scu.filter_start_addr = + readl(context_scu.base + SCU_FILTER_STARTADDR); + context_scu.filter_end_addr = + readl(context_scu.base + SCU_FILTER_ENDADDR); + context_scu.access_ctrl_sac = + readl(context_scu.base + SCU_ACCESS_CTRL_SAC); +} + +static void restore_scu(void) +{ + writel(context_scu.ctrl, + context_scu.base + SCU_CTRL); + writel(context_scu.cpu_pwrstatus, + context_scu.base + SCU_CPU_STATUS); + writel(context_scu.inv_all_nonsecure, + context_scu.base + SCU_INVALIDATE); + writel(context_scu.filter_start_addr, + context_scu.base + SCU_FILTER_STARTADDR); + writel(context_scu.filter_end_addr, + context_scu.base + SCU_FILTER_ENDADDR); + writel(context_scu.access_ctrl_sac, + context_scu.base + SCU_ACCESS_CTRL_SAC); +} + +/* + * Save VAPE context + */ +void context_vape_save(void) +{ + atomic_notifier_call_chain(&context_ape_notifier_list, + CONTEXT_APE_SAVE, NULL); + + if (cpu_is_u5500()) + u5500_context_save_icn(); + if (cpu_is_u8500()) + u8500_context_save_icn(); + + save_stm_ape(); + + save_tpiu(); + + save_prcc(); + +} + +/* + * Restore VAPE context + */ +void context_vape_restore(void) +{ + restore_prcc(); + + restore_tpiu(); + + restore_stm_ape(); + + if (cpu_is_u5500()) + u5500_context_restore_icn(); + if (cpu_is_u8500()) + u8500_context_restore_icn(); + + atomic_notifier_call_chain(&context_ape_notifier_list, + CONTEXT_APE_RESTORE, NULL); +} + +/* + * Save GPIO registers that might be modified + * for power save reasons. + */ +void context_gpio_save(void) +{ + int i; + + for (i = 0; i < GPIO_NUM_BANKS; i++) { + gpio_save[i][0] = readl(gpio_bankaddr[i] + NMK_GPIO_AFSLA); + gpio_save[i][1] = readl(gpio_bankaddr[i] + NMK_GPIO_AFSLB); + gpio_save[i][2] = readl(gpio_bankaddr[i] + NMK_GPIO_PDIS); + gpio_save[i][3] = readl(gpio_bankaddr[i] + NMK_GPIO_DIR); + gpio_save[i][4] = readl(gpio_bankaddr[i] + NMK_GPIO_DAT); + gpio_save[i][6] = readl(gpio_bankaddr[i] + NMK_GPIO_SLPC); + } +} + +/* + * Restore GPIO registers that might be modified + * for power save reasons. + */ +void context_gpio_restore(void) +{ + int i; + u32 output_state; + u32 pull_up; + u32 pull_down; + u32 pull; + + for (i = 0; i < GPIO_NUM_BANKS; i++) { + writel(gpio_save[i][2], gpio_bankaddr[i] + NMK_GPIO_PDIS); + + writel(gpio_save[i][3], gpio_bankaddr[i] + NMK_GPIO_DIR); + + /* Set the high outputs. outpute_state = GPIO_DIR & GPIO_DAT */ + output_state = gpio_save[i][3] & gpio_save[i][4]; + writel(output_state, gpio_bankaddr[i] + NMK_GPIO_DATS); + + /* + * Set the low outputs. + * outpute_state = ~(GPIO_DIR & GPIO_DAT) & GPIO_DIR + */ + output_state = ~(gpio_save[i][3] & gpio_save[i][4]) & + gpio_save[i][3]; + writel(output_state, gpio_bankaddr[i] + NMK_GPIO_DATC); + + /* + * Restore pull up/down. + * Only write pull up/down settings on inputs where + * PDIS is not set. + * pull = (~GPIO_DIR & ~GPIO_PDIS) + */ + pull = (~gpio_save[i][3] & ~gpio_save[i][2]); + nmk_gpio_read_pull(i, &pull_up); + + pull_down = pull & ~pull_up; + pull_up = pull & pull_up; + /* Set pull ups */ + writel(pull_up, gpio_bankaddr[i] + NMK_GPIO_DATS); + /* Set pull downs */ + writel(pull_down, gpio_bankaddr[i] + NMK_GPIO_DATC); + + writel(gpio_save[i][6], gpio_bankaddr[i] + NMK_GPIO_SLPC); + + } + +} + +/* + * Restore GPIO mux registers that might be modified + * for power save reasons. + */ +void context_gpio_restore_mux(void) +{ + int i; + + /* Change mux settings */ + for (i = 0; i < GPIO_NUM_BANKS; i++) { + writel(gpio_save[i][0], gpio_bankaddr[i] + NMK_GPIO_AFSLA); + writel(gpio_save[i][1], gpio_bankaddr[i] + NMK_GPIO_AFSLB); + } +} + +/* + * Safe sequence used to switch IOs between GPIO and Alternate-C mode: + * - Save SLPM registers (Not done.) + * - Set SLPM=0 for the IOs you want to switch. (We assume that all + * SLPM registers already are 0 except for the ones that wants to + * have the mux connected in sleep (e.g modem STM)). + * - Configure the GPIO registers for the IOs that are being switched + * - Set IOFORCE=1 + * - Modify the AFLSA/B registers for the IOs that are being switched + * - Set IOFORCE=0 + * - Restore SLPM registers (Not done.) + * - Any spurious wake up event during switch sequence to be ignored + * and cleared + */ +void context_gpio_mux_safe_switch(bool begin) +{ + int i; + + static u32 rwimsc[GPIO_NUM_BANKS]; + static u32 fwimsc[GPIO_NUM_BANKS]; + + if (begin) { + for (i = 0; i < GPIO_NUM_BANKS; i++) { + /* Save registers */ + rwimsc[i] = readl(gpio_bankaddr[i] + NMK_GPIO_RWIMSC); + fwimsc[i] = readl(gpio_bankaddr[i] + NMK_GPIO_FWIMSC); + + /* Prevent spurious wakeups */ + writel(0, gpio_bankaddr[i] + NMK_GPIO_RWIMSC); + writel(0, gpio_bankaddr[i] + NMK_GPIO_FWIMSC); + } + + ux500_pm_prcmu_set_ioforce(true); + } else { + ux500_pm_prcmu_set_ioforce(false); + + /* Restore wake up settings */ + for (i = 0; i < GPIO_NUM_BANKS; i++) { + writel(rwimsc[i], gpio_bankaddr[i] + NMK_GPIO_RWIMSC); + writel(fwimsc[i], gpio_bankaddr[i] + NMK_GPIO_FWIMSC); + } + + } + +} + +/* + * Save common + * + * This function must be called once for all cores before going to deep sleep. + */ +void context_varm_save_common(void) +{ + atomic_notifier_call_chain(&context_arm_notifier_list, + CONTEXT_ARM_COMMON_SAVE, NULL); + + /* Save common parts */ + save_gic_dist_common(); + save_scu(); +} + +/* + * Restore common + * + * This function must be called once for all cores when waking up from deep + * sleep. + */ +void context_varm_restore_common(void) +{ + /* Restore common parts */ + restore_scu(); + restore_gic_dist_common(); + + atomic_notifier_call_chain(&context_arm_notifier_list, + CONTEXT_ARM_COMMON_RESTORE, NULL); +} + +/* + * Save core + * + * This function must be called once for each cpu core before going to deep + * sleep. + */ +void context_varm_save_core(void) +{ + int cpu = smp_processor_id(); + + atomic_notifier_call_chain(&context_arm_notifier_list, + CONTEXT_ARM_CORE_SAVE, NULL); + + per_cpu(varm_cp15_pointer, cpu) = per_cpu(varm_cp15_backup_stack, cpu); + + /* Save core */ + save_gic_if_cpu(&per_cpu(context_gic_cpu, cpu)); + save_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu)); + context_save_cp15_registers(&per_cpu(varm_cp15_pointer, cpu)); +} + +/* + * Restore core + * + * This function must be called once for each cpu core when waking up from + * deep sleep. + */ +void context_varm_restore_core(void) +{ + int cpu = smp_processor_id(); + + /* Restore core */ + context_restore_cp15_registers(&per_cpu(varm_cp15_pointer, cpu)); + restore_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu)); + restore_gic_if_cpu(&per_cpu(context_gic_cpu, cpu)); + + atomic_notifier_call_chain(&context_arm_notifier_list, + CONTEXT_ARM_CORE_RESTORE, NULL); + +} + +/* + * Save CPU registers + * + * This function saves ARM registers. + */ +void context_save_cpu_registers(void) +{ + int cpu = smp_processor_id(); + + per_cpu(varm_registers_pointer, cpu) = + per_cpu(varm_registers_backup_stack, cpu); + context_save_arm_registers(&per_cpu(varm_registers_pointer, cpu)); +} + +/* + * Restore CPU registers + * + * This function restores ARM registers. + */ +void context_restore_cpu_registers(void) +{ + int cpu = smp_processor_id(); + + context_restore_arm_registers(&per_cpu(varm_registers_pointer, cpu)); +} + +/* + * This function stores CP15 registers related to cache and mmu + * in backup SRAM. It also stores stack pointer, CPSR + * and return address for the PC in backup SRAM and + * does wait for interrupt. + */ +void context_save_to_sram_and_wfi(bool cleanL2cache) +{ + int cpu = smp_processor_id(); + + if (cpu_is_u8500()) + context_save_to_sram_and_wfi_internal(backup_sram_storage[cpu], + cleanL2cache); + else if (cpu_is_u5500()) + __asm__ __volatile__("wfi\n" : : : "memory"); +} + +static int __init context_init(void) +{ + int i; + void __iomem *ux500_backup_ptr; + + /* allocate backup pointer for RAM data */ + ux500_backup_ptr = (void *)__get_free_pages(GFP_KERNEL, + get_order(U8500_BACKUPRAM_SIZE)); + + if (!ux500_backup_ptr) { + pr_warning("context: could not allocate backup memory\n"); + return -ENOMEM; + } + + /* + * ROM code addresses to store backup contents, + * pass the physical address of back up to ROM code + */ + writel(virt_to_phys(ux500_backup_ptr), + IO_ADDRESS(U8500_EXT_RAM_LOC_BACKUPRAM_ADDR)); + + /* Give logical address to backup RAM. For both CPUs */ + if (cpu_is_u8500v20_or_later()) { + writel(IO_ADDRESS(U8500_PUBLIC_BOOT_ROM_BASE), + IO_ADDRESS(U8500_CPU0_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); + + writel(IO_ADDRESS(U8500_PUBLIC_BOOT_ROM_BASE), + IO_ADDRESS(U8500_CPU1_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); + } else { + writel(IO_ADDRESS(U8500_BACKUPRAM0_BASE), + IO_ADDRESS(U8500_CPU0_BACKUPRAM_ADDR_BACKUPRAM_LOG_ADDR)); + + writel(IO_ADDRESS(U8500_BACKUPRAM0_BASE), + IO_ADDRESS(U8500_CPU1_BACKUPRAM_ADDR_BACKUPRAM_LOG_ADDR)); + } + + /* FIXME: To UX500 */ + context_tpiu.base = ioremap(U8500_TPIU_BASE, SZ_4K); + context_stm_ape.base = ioremap(U8500_STM_REG_BASE, SZ_4K); + context_scu.base = ioremap(U8500_SCU_BASE, SZ_4K); + + for (i = 0; i < num_possible_cpus(); i++) { + per_cpu(context_gic_cpu, i).base = ioremap(U8500_GIC_CPU_BASE, + SZ_4K); + per_cpu(context_gic_dist_cpu, i).base = + ioremap(U8500_GIC_DIST_BASE, + SZ_4K); + } + + context_gic_dist_common.base = ioremap(U8500_GIC_DIST_BASE, SZ_4K); + + /* PERIPH4 is always on, so no need saving prcc */ + context_prcc[0].base = ioremap(U8500_CLKRST1_BASE, SZ_4K); + context_prcc[1].base = ioremap(U8500_CLKRST2_BASE, SZ_4K); + context_prcc[2].base = ioremap(U8500_CLKRST3_BASE, SZ_4K); + context_prcc[3].base = ioremap(U8500_CLKRST5_BASE, SZ_4K); + context_prcc[4].base = ioremap(U8500_CLKRST6_BASE, SZ_4K); + + for (i = 0; i < ARRAY_SIZE(context_prcc); i++) { + const int clusters[] = {1, 2, 3, 5, 6}; + char clkname[10]; + + snprintf(clkname, sizeof(clkname), "PERIPH%d", clusters[i]); + + context_prcc[i].clk = clk_get_sys(clkname, NULL); + BUG_ON(IS_ERR(context_prcc[i].clk)); + } + + if (cpu_is_u8500()) { + u8500_context_init(); + } else if (cpu_is_u5500()) { + u5500_context_init(); + } else { + printk(KERN_ERR "context: unknown hardware!\n"); + return -EINVAL; + } + + return 0; +} +subsys_initcall(context_init); diff --git a/arch/arm/mach-ux500/pm/context.h b/arch/arm/mach-ux500/pm/context.h new file mode 100644 index 00000000000..20ffaafdb41 --- /dev/null +++ b/arch/arm/mach-ux500/pm/context.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> + * Rickard Andersson <rickard.andersson@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ +#ifndef CONTEXT_H +#define CONTEXT_H + +#include <linux/notifier.h> + +#ifdef CONFIG_UX500_CONTEXT + +/* Defines to be with + * context_ape_notifier_register + */ +#define CONTEXT_APE_SAVE 0 /* APE save */ +#define CONTEXT_APE_RESTORE 1 /* APE restore */ + +/* Defines to be with + * context_arm_notifier_register + */ +#define CONTEXT_ARM_CORE_SAVE 0 /* Called for each ARM core */ +#define CONTEXT_ARM_CORE_RESTORE 1 /* Called for each ARM core */ +#define CONTEXT_ARM_COMMON_SAVE 2 /* Called when ARM common is saved */ +#define CONTEXT_ARM_COMMON_RESTORE 3 /* Called when ARM common is restored */ + +int context_ape_notifier_register(struct notifier_block *nb); +int context_ape_notifier_unregister(struct notifier_block *nb); + +int context_arm_notifier_register(struct notifier_block *nb); +int context_arm_notifier_unregister(struct notifier_block *nb); + +void context_vape_save(void); +void context_vape_restore(void); + +void context_gpio_save(void); +void context_gpio_restore(void); +void context_gpio_restore_mux(void); +void context_gpio_mux_safe_switch(bool begin); + +void context_varm_save_common(void); +void context_varm_restore_common(void); + +void context_varm_save_core(void); +void context_varm_restore_core(void); + +void context_save_cpu_registers(void); +void context_restore_cpu_registers(void); + +/* + * cleanL2cache - Indicate if L2 cache should be cleaned. + * Note that L1 cache is always cleaned. + */ +void context_save_to_sram_and_wfi(bool cleanL2cache); + +void context_clean_l1_cache_all(void); +void context_save_arm_registers(u32 **backup_stack); +void context_restore_arm_registers(u32 **backup_stack); + +void context_save_cp15_registers(u32 **backup_stack); +void context_restore_cp15_registers(u32 **backup_stack); + +void context_save_to_sram_and_wfi_internal(u32 backup_sram_storage, + bool cleanL2cache); + +/* DB specific functions in either context-db8500 or context-db5500 */ +void u8500_context_save_icn(void); +void u8500_context_restore_icn(void); +void u8500_context_init(void); + +void u5500_context_save_icn(void); +void u5500_context_restore_icn(void); +void u5500_context_init(void); + +#else + +static inline void context_varm_save_core(void) {} +static inline void context_save_cpu_registers(void) {} +static inline void context_save_to_sram_and_wfi(bool cleanL2cache) {} +static inline void context_restore_cpu_registers(void) {} +static inline void context_varm_restore_core(void) {} + +#endif + +#endif diff --git a/arch/arm/mach-ux500/pm/context_arm.S b/arch/arm/mach-ux500/pm/context_arm.S new file mode 100644 index 00000000000..7778b3d4503 --- /dev/null +++ b/arch/arm/mach-ux500/pm/context_arm.S @@ -0,0 +1,427 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> + * Rickard Andersson <rickard.andersson@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#include <linux/linkage.h> +#include <mach/hardware.h> +#include <asm/hardware/cache-l2x0.h> + +/* + * Save and increment macro + */ +.macro SAVE_AND_INCREMENT FROM_REG TO_REG + str \FROM_REG, [\TO_REG], #+4 +.endm + +/* + * Decrement and restore macro + */ +.macro DECREMENT_AND_RESTORE FROM_REG TO_REG + ldr \TO_REG, [\FROM_REG, #-4]! +.endm + +/* + * Save ARM registers + * + * This function must be called in supervisor mode. + * + * r0 = address to backup stack pointer + * + * Backup stack operations: + * + {sp, lr}^ + * + cpsr + * + {r3, r8-r14} (FIQ mode: r3=spsr) + * + {r3, r13, r14} (IRQ mode: r3=spsr) + * + {r3, r13, r14} (abort mode: r3=spsr) + * + {r3, r13, r14} (undef mode: r3=spsr) + */ + .align + .section ".text", "ax" +ENTRY(context_save_arm_registers) + stmfd sp!, {r1, r2, r3, lr} @ Save on stack + ldr r1, [r0] @ Read backup stack pointer + + stmia r1, {sp, lr}^ @ Store user mode sp and lr + @ registers + add r1, r1, #8 @ Update backup pointer (not + @ done in previous instruction) + + mrs r2, cpsr @ Get CPSR + SAVE_AND_INCREMENT r2 r1 @ Save CPSR register + orr r2, r2, #0xc0 @ Disable FIQ and IRQ + bic r2, r2, #0x1f @ Setup r2 to change mode + + @ The suffix to CPSR refers to which field(s) of the CPSR is + @ rereferenced (you can specify one or more). Defined fields are: + @ + @ c - control + @ x - extension + @ s - status + @ f - flags + + orr r3, r2, #0x11 @ Save FIQ mode registers + msr cpsr_cxsf, r3 + mrs r3, spsr + stmia r1!, {r3, r8-r14} + + orr r3, r2, #0x12 @ Save IRQ mode registers + msr cpsr_cxsf, r3 + mrs r3, spsr + stmia r1!, {r3, r13, r14} + + orr r3, r2, #0x17 @ Save abort mode registers + + @ common mode registers + msr cpsr_cxsf, r3 + mrs r3, spsr + stmia r1!, {r3, r13, r14} + + orr r3, r2, #0x1B @ Save undef mode registers + msr cpsr_cxsf, r3 + mrs r3, spsr + stmia r1!, {r3, r13, r14} + + orr r3, r2, #0x13 @ Return to supervisor mode + msr cpsr_cxsf, r3 + + str r1, [r0] @ Write backup stack pointer + ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return + + + +/* + * Restore ARM registers + * + * This function must be called in supervisor mode. + * + * r0 = address to backup stack pointer + * + * Backup stack operations: + * - {r3, r13, r14} (undef mode: spsr=r3) + * - {r3, r13, r14} (abort mode: spsr=r3) + * - {r3, r13, r14} (IRQ mode: spsr=r3) + * - {r3, r8-r14} (FIQ mode: spsr=r3) + * - cpsr + * - {sp, lr}^ + */ + .align + .section ".text", "ax" +ENTRY(context_restore_arm_registers) + stmfd sp!, {r1, r2, r3, lr} @ Save on stack + ldr r1, [r0] @ Read backup stack pointer + + mrs r2, cpsr @ Get CPSR + orr r2, r2, #0xc0 @ Disable FIQ and IRQ + bic r2, r2, #0x1f @ Setup r2 to change mode + + orr r3, r2, #0x1b @ Restore undef mode registers + msr cpsr_cxsf, r3 + ldmdb r1!, {r3, r13, r14} + msr spsr_cxsf, r3 + + orr r3, r2, #0x17 @ Restore abort mode registers + msr cpsr_cxsf, r3 + ldmdb r1!, {r3, r13, r14} + msr spsr_cxsf, r3 + + orr r3, r2, #0x12 @ Restore IRQ mode registers + msr cpsr_cxsf, r3 + ldmdb r1!, {r3, r13, r14} + msr spsr_cxsf, r3 + + orr r3, r2, #0x11 @ Restore FIQ mode registers + msr cpsr_cxsf, r3 + ldmdb r1!, {r3, r8-r14} + msr spsr_cxsf, r3 + + DECREMENT_AND_RESTORE r1 r3 @ Restore cpsr register + msr cpsr_cxsf, r3 + + ldmdb r1, {sp, lr}^ @ Restore sp and lr registers + sub r1, r1, #8 @ Update backup pointer (not + @ done in previous instruction) + + str r1, [r0] @ Write backup stack pointer + ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return + + + +/* + * Save CP15 registers + * + * This function must be called in supervisor mode. + * + * r0 = address to backup stack pointer + * + * TTBR0, TTBR1, TTBRC, DACR CP15 registers are restored by boot ROM from SRAM. + */ + .align 4 + .section ".text", "ax" +ENTRY(context_save_cp15_registers) + stmfd sp!, {r1, r2, lr} @ Save on stack + ldr r1, [r0] @ Read backup stack pointer + + mrc p15, 0, r2, c12, c0, 0 @ Read Non-secure Vector Base + @ Address Register + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 0, r2, c10, c2, 0 @ Access primary memory region + @ remap register + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 0, r2, c10, c2, 1 @ Access normal memory region + @ remap register + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 0, r2, c13, c0, 1 @ Read Context ID Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c13, c0, 2 @ Read Thread ID registers, + @ this register is both user + @ and privileged R/W accessible + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c13, c0, 3 @ Read Thread ID registers, + @ this register is user + @ read-only and privileged R/W + @ accessible. + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c13, c0, 4 @ Read Thread ID registers, + @ this register is privileged + @ R/W accessible only. + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 0, r2, c9, c12, 0 @ Read PMNC Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c12, 1 @ Read PMCNTENSET Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c12, 5 @ Read PMSELR Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c13, 0 @ Read PMCCNTR Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c13, 1 @ Read PMXEVTYPER Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c14, 0 @ Read PMUSERENR Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c14, 1 @ Read PMINTENSET Register + SAVE_AND_INCREMENT r2 r1 + mrc p15, 0, r2, c9, c14, 2 @ Read PMINTENCLR Register + SAVE_AND_INCREMENT r2 r1 + + mrc p15, 0, r2, c1, c0, 2 @ Read CPACR Register + SAVE_AND_INCREMENT r2 r1 + + str r1, [r0] @ Write backup stack pointer + ldmfd sp!, {r1, r2, pc} @ Restore registers and return + + + +/* + * Restore CP15 registers + * + * This function must be called in supervisor mode. + * + * r0 = address to backup stack pointer + */ + .align 4 + .section ".text", "ax" +ENTRY(context_restore_cp15_registers) + stmfd sp!, {r1, r2, lr} @ Save on stack + ldr r1, [r0] @ Read backup stack pointer + + DECREMENT_AND_RESTORE r1 r2 @ Write CPACR register + mcr p15, 0, r2, c1, c0, 2 + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c14, 2 @ Write PMINTENCLR Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c14, 1 @ Write PMINTENSET Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c14, 0 @ Write PMUSERENR Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c13, 1 @ Write PMXEVTYPER Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c13, 0 @ Write PMCCNTR Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c12, 5 @ Write PMSELR Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c12, 1 @ Write PMCNTENSET Register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c9, c12, 0 @ Write PMNC Register + + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register + + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c13, c0, 4 @ Write Thread ID registers, + @ this register is privileged + @ R/W accessible only + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c13, c0, 3 @ Write Thread ID registers, + @ this register is user + @ read-only and privileged R/W + @ accessible + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c13, c0, 2 @ Write Thread ID registers, + @ this register is both user + @ and privileged R/W accessible + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c13, c0, 1 @ Write Context ID Register + + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c10, c2, 1 @ Access normal memory region + @ remap register + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c10, c2, 0 @ Access primary memory region + @ remap register + + DECREMENT_AND_RESTORE r1 r2 + mcr p15, 0, r2, c12, c0, 0 @ Write Non-secure Vector Base + @ Address Register + + str r1, [r0] @ Write backup stack pointer + ldmfd sp!, {r1, r2, pc} @ Restore registers and return + + +/* + * L1 cache clean function. Commit 'dirty' data from L1 + * to L2 cache. + * + * r0, r1, r2, used locally + * + */ + .align 4 + .section ".text", "ax" +ENTRY(context_clean_l1_cache_all) + + mov r0, #0 @ swith to cache level 0 + @ (L1 cache) + mcr p15, 2, r0, c0, c0, 0 @ select current cache level + @ in cssr + + dmb + mov r1, #0 @ r1 = way index +wayLoopL1clean: + mov r0, #0 @ r0 = line index +lineLoopL1clean: + mov r2, r1, lsl #30 @ TODO: OK to hard-code + @ SoC-specific L1 cache details? + add r2, r0, lsl #5 + mcr p15, 0, r2, c7, c10, 2 @ Clean cache by set/way + add r0, r0, #1 + cmp r0, #256 @ TODO: Ok with hard-coded + @ set/way sizes or do we have to + @ read them from ARM regs? Is it + @ set correctly in silicon? + bne lineLoopL1clean + add r1, r1, #1 + cmp r1, #4 @ TODO: Ditto, sizes... + bne wayLoopL1clean + + dsb + isb + mov pc, lr + +ENDPROC(context_clean_l1_cache_all) + + +/* + * L2 cache clean function. Commit from PL310 L2 cache + * controller to DDR SDRAM. + * + * r0, r2 used locally + * + */ + .align 4 + .section ".text", "ax" +ENTRY(ux500_clean_l2_cache_all) + + ldr r0, =IO_ADDRESS(U8500_L2CC_BASE) + + ldr r1, =0xff @ TODO: Ok to assume 8-way cache + @ on Ux500? + str r1, [r0, #L2X0_CLEAN_WAY] + L2busywaitLoopClean: + ldr r1, [r0, #L2X0_CLEAN_WAY] + cmp r1, #0 @ All bits in L2X0_CLEAN_WAY + @ will be zero once clean is + @ finished + bne L2busywaitLoopClean + + ldr r1, =0x0 + str r1, [r0, #L2X0_CACHE_SYNC] + @ l2x0 C code busy-wait here to + @ ensure no background op is + @ running. + @ In our case we have already + @ checked this after the cache + @ clean and CACHE_SYNC is atomic + @ according to refman + mov pc, lr + + +/* + * Last saves and WFI + * + * r0 = address to backup_sram_storage base adress + * r1 = indicate whether L1 and L2 cache should be cleaned + */ + .align 4 + .section ".text", "ax" +ENTRY(context_save_to_sram_and_wfi_internal) + + stmfd sp!, {r2-r12, lr} @ save on stack. + + mrc p15, 0, r2, c1, c0, 0 @ read cp15 system control + @ register + str r2, [r0, #0x00] + mrc p15, 0, r2, c2, c0, 0 @ read cp15 ttb0 register + str r2, [r0, #0x04] + mrc p15, 0, r2, c2, c0, 1 @ read cp15 ttb1 register + str r2, [r0, #0x08] + mrc p15, 0, r2, c2, c0, 2 @ read cp15 ttb control register + str r2, [r0, #0x0C] + mrc p15, 0, r2, c3, c0, 0 @ read domain access control + @ register + str r2, [r0, #0x10] + + ldr r2, =return_here + str r2, [r0, #0x14] @ save program counter restore + @ value to backup_sram_storage + mrs r2, cpsr + str r2, [r0, #0x18] @ save cpsr to + @ backup_sram_storage + str sp, [r0, #0x1c] @ save sp to backup_sram_storage + + mov r4, r1 @ Set r4 = cleanL2cache, r2 + @ will be destroyed by + @ v7_clean_l1_cache_all + dsb + cmp r4, #0 + + blne context_clean_l1_cache_all @ Commit all dirty data in L1 + @ cache to L2 without + @ invalidating + dsb + cmp r4, #0 + + blne ux500_clean_l2_cache_all @ If r2 != FALSE then clean all + @ dirty data in L2 cache, no + @ invalidate + + dsb @ data synchronization barrier + isb @ instruction synchronization + @ barrier + wfi @ wait for interrupt + +return_here: @ both cores return here + @ now we are out deep sleep + @ with all the context lost + @ except pc, sp and cpsr + + ldmfd sp!, {r2-r12, pc} @ restore from stack + diff --git a/arch/arm/mach-ux500/pm/cpufreq-db8500.c b/arch/arm/mach-ux500/pm/cpufreq-db8500.c new file mode 100644 index 00000000000..c5f16a373ce --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpufreq-db8500.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ + +#include <linux/kernel.h> +#include <linux/cpufreq.h> + +#include <mach/prcmu-fw-api.h> + +#include "cpufreq.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 int __init u8500_cpufreq_register(void) +{ + 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; + } + + return ux500_cpufreq_register(freq_table, idx2opp); +} +device_initcall(u8500_cpufreq_register); diff --git a/arch/arm/mach-ux500/pm/cpufreq.c b/arch/arm/mach-ux500/pm/cpufreq.c new file mode 100644 index 00000000000..1f5999e8271 --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpufreq.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * + */ +#include <linux/kernel.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/slab.h> + +#include <mach/hardware.h> +#include <mach/prcmu-fw-api.h> +#include <mach/prcmu-regs.h> + +static struct cpufreq_frequency_table *freq_table; +static enum arm_opp *idx2opp; + +static struct freq_attr *u8500_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +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 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("u8500-cpufreq: Failed to set OPP level\n"); + return -EINVAL; + } + + /* post change notification */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static unsigned int u8500_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 u8500_cpufreq_init(struct cpufreq_policy *policy) +{ + int res; + int i; + + /* 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("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); + + 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 u8500_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = u8500_cpufreq_verify_speed, + .target = u8500_cpufreq_target, + .get = u8500_cpufreq_getspeed, + .init = u8500_cpufreq_init, + .name = "U8500", + .attr = u8500_cpufreq_attr, +}; + +int __init +ux500_cpufreq_register(struct cpufreq_frequency_table *table, + enum arm_opp *idx2opplist) +{ + freq_table = table; + idx2opp = idx2opplist; + + if (ux500_is_svp()) + return -ENODEV; + + pr_info("cpufreq for u8500 started\n"); + return cpufreq_register_driver(&u8500_cpufreq_driver); +} diff --git a/arch/arm/mach-ux500/pm/cpufreq.h b/arch/arm/mach-ux500/pm/cpufreq.h new file mode 100644 index 00000000000..dc8744078f5 --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpufreq.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ +#ifndef __UX500_PM_CPUFREQ_H +#define __UX500_PM_CPUFREQ_H + +extern int ux500_cpufreq_register(struct cpufreq_frequency_table *freq_table, + enum arm_opp *idx2opp); + +#endif diff --git a/arch/arm/mach-ux500/pm/cpuidle.c b/arch/arm/mach-ux500/pm/cpuidle.c new file mode 100644 index 00000000000..97ac7bd2fff --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpuidle.c @@ -0,0 +1,732 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010-2011 + * + * Author: Rickard Andersson <rickard.andersson@stericsson.com>, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson. + * + * Loosely based on cpuidle.c by Sundar Iyer. + * + * License terms: GNU General Public License (GPL) version 2 + * + */ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/tick.h> +#include <linux/clockchips.h> + +#include <plat/gpio.h> + +#include <mach/prcmu-fw-api.h> + +#include "cpuidle.h" +#include "cpuidle_dbg.h" +#include "context.h" +#include "pm.h" +#include "../regulator-u8500.h" + +#define DEEP_SLEEP_WAKE_UP_LATENCY 8500 +#define SLEEP_WAKE_UP_LATENCY 800 +#define UL_PLL_START_UP_LATENCY 8000 /* us */ + +static struct cstate cstates[] = { + { + .enter_latency = 0, + .exit_latency = 0, + .threshold = 0, + .power_usage = 1000, + .APE = APE_ON, + .ARM = ARM_ON, + .ARM_PLL = ARM_PLL_ON, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = NO_TRANSITION, + .flags = CPUIDLE_FLAG_POLL, + .state = CI_RUNNING, + .desc = "Running ", + }, + { + .enter_latency = 0, + .exit_latency = 0, + .threshold = 0, + .power_usage = 10, + .APE = APE_ON, + .ARM = ARM_ON, + .ARM_PLL = ARM_PLL_ON, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = NO_TRANSITION, + .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID, + .state = CI_WFI, + .desc = "Wait for interrupt ", + }, + { + .enter_latency = 40, + .exit_latency = 50, + .threshold = 150, + .power_usage = 5, + .APE = APE_ON, + .ARM = ARM_RET, + .ARM_PLL = ARM_PLL_ON, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_IDLE, + .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID, + .state = CI_IDLE, + .desc = "ApIdle ", + }, + { + .enter_latency = 45, + .exit_latency = 50, + .threshold = 160, + .power_usage = 4, + .APE = APE_ON, + .ARM = ARM_RET, + .ARM_PLL = ARM_PLL_OFF, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_IDLE, + .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID, + .state = CI_IDLE, + .desc = "ApIdle, ARM PLL off ", + }, + { + .enter_latency = 120, + .exit_latency = SLEEP_WAKE_UP_LATENCY, + /* + * Note: Sleep time must be longer than 120 us or else + * there might be issues with the RTC-RTT block. + */ + .threshold = SLEEP_WAKE_UP_LATENCY + 120 + 50, + .power_usage = 3, + .APE = APE_OFF, + .ARM = ARM_RET, + .ARM_PLL = ARM_PLL_OFF, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_SLEEP, + .flags = CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_TIME_VALID, + .state = CI_SLEEP, + .desc = "ApSleep ", + }, + { + .enter_latency = 150, + .exit_latency = (SLEEP_WAKE_UP_LATENCY + + UL_PLL_START_UP_LATENCY), + .threshold = (2 * (SLEEP_WAKE_UP_LATENCY + + UL_PLL_START_UP_LATENCY + 50)), + .power_usage = 2, + .APE = APE_OFF, + .ARM = ARM_RET, + .ARM_PLL = ARM_PLL_OFF, + .UL_PLL = UL_PLL_OFF, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_SLEEP, + .flags = CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_TIME_VALID, + .state = CI_SLEEP, + .desc = "ApSleep, UL PLL off ", + }, +#ifdef ENABLE_AP_DEEP_IDLE + { + .enter_latency = 160, + .exit_latency = DEEP_SLEEP_WAKE_UP_LATENCY, + .threshold = DEEP_SLEEP_WAKE_UP_LATENCY + 160 + 50, + .power_usage = 2, + .APE = APE_ON, + .ARM = ARM_OFF, + .ARM_PLL = ARM_PLL_OFF, + .UL_PLL = UL_PLL_ON, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_DEEP_IDLE, + .flags = CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_TIME_VALID, + .state = CI_DEEP_IDLE, + .desc = "ApDeepIdle, UL PLL off ", + }, +#endif + { + .enter_latency = 200, + .exit_latency = DEEP_SLEEP_WAKE_UP_LATENCY, + .threshold = DEEP_SLEEP_WAKE_UP_LATENCY + 200 + 50, + .power_usage = 1, + .APE = APE_OFF, + .ARM = ARM_OFF, + .ARM_PLL = ARM_PLL_OFF, + .UL_PLL = UL_PLL_OFF, + .ESRAM = ESRAM_RET, + .pwrst = PRCMU_AP_DEEP_SLEEP, + .flags = CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_TIME_VALID, + .state = CI_DEEP_SLEEP, + .desc = "ApDeepsleep, UL PLL off", + }, +}; + +struct cpu_state { + int gov_cstate; + ktime_t sched_wake_up; + struct cpuidle_device dev; +}; + +static DEFINE_PER_CPU(struct cpu_state, *cpu_state); + +static DEFINE_SPINLOCK(cpuidle_lock); +static bool restore_ape; /* protected by cpuidle_lock */ +static bool restore_arm; /* protected by cpuidle_lock */ + +extern struct clock_event_device u8500_rtt_clkevt; +extern struct clock_event_device u8500_mtu_clkevt; + +static atomic_t idle_cpus_counter = ATOMIC_INIT(0); +static ktime_t time_zero; + +struct cstate *ux500_ci_get_cstates(int *len) +{ + if (len != NULL) + (*len) = ARRAY_SIZE(cstates); + return cstates; +} + +static void do_nothing(void *unused) +{ +} + +/* + * cpuidle & hotplug - plug or unplug a cpu in idle sequence + */ +void ux500_cpuidle_plug(int cpu) +{ + atomic_dec(&idle_cpus_counter); + wmb(); +} +void ux500_cpuidle_unplug(int cpu) +{ + atomic_inc(&idle_cpus_counter); + wmb(); +} + +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ +void cpu_idle_wait(void) +{ + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 1); +} + +static void restore_sequence(struct cpu_state *state, + bool always_on_timer_migrated) +{ + unsigned long iflags; + int this_cpu = smp_processor_id(); + + spin_lock_irqsave(&cpuidle_lock, iflags); + + smp_rmb(); + if (restore_arm) { + + restore_arm = false; + smp_wmb(); + + context_varm_restore_core(); + /* Restore gic settings */ + context_varm_restore_common(); + } + + smp_rmb(); + if (restore_ape) { + /* Wake in 1 us */ + ktime_t time_next = ktime_set(0, 1000); + + restore_ape = false; + smp_wmb(); + + /* + * APE has been turned off. Save GPIO wake up cause before + * clearing ioforce. + */ + context_vape_restore(); + + ux500_pm_gpio_save_wake_up_status(); + + /* Restore IO ring */ + ux500_pm_prcmu_set_ioforce(false); + + ux500_ci_dbg_console_handle_ape_resume(); + + clockevents_set_mode(&u8500_rtt_clkevt, + CLOCK_EVT_MODE_SHUTDOWN); + /* + * TODO: We might have woken on other interrupt. + * Reprogram MTU to wake at correct time. + */ + + /* Make sure have an MTU interrupt waiting for us */ + clockevents_program_event(&u8500_mtu_clkevt, + time_next, + time_zero); + } + + /* + * TODO: Figure out why the second CPU does not get scheduled + * when it should be the first one out of ApSleep. + * (First cpu gets all shared interrupts.) + */ + + if (this_cpu == 0) { + int cpu; + for_each_online_cpu(cpu) { + /* TODO: Only kick the CPU that was supposed to wake */ + if (cpu != this_cpu) + /* Send an unused IPI interrupt (2) */ + gic_raise_softirq(cpumask_of(cpu), 2); + } + } + + spin_unlock_irqrestore(&cpuidle_lock, iflags); + + smp_rmb(); + if (always_on_timer_migrated) { + /* Use the ARM local timer for this cpu */ + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + &this_cpu); + } +} + +/** + * get_remaining_sleep_time() - returns remaining sleep time in + * microseconds (us) + */ +static int get_remaining_sleep_time(void) +{ + ktime_t now; + int cpu; + unsigned long iflags; + int t; + int remaining_sleep_time = INT_MAX; + + now = ktime_get(); + + /* Check next schedule to expire considering both cpus */ + + spin_lock_irqsave(&cpuidle_lock, iflags); + for_each_online_cpu(cpu) { + t = ktime_to_us(ktime_sub(per_cpu(cpu_state, + cpu)->sched_wake_up, + now)); + if ((t < remaining_sleep_time) && (t > 0)) + remaining_sleep_time = t; + } + spin_unlock_irqrestore(&cpuidle_lock, iflags); + + return remaining_sleep_time; +} + +static int determine_sleep_state(void) +{ + int i; + int sleep_time; + int cpu; + int max_depth; + bool power_state_req; + + /* If first cpu to sleep, go to most shallow sleep state */ + if (atomic_read(&idle_cpus_counter) < num_online_cpus()) + return CI_WFI; + + /* If other CPU is going to WFI, but not yet there wait. */ + while (1) { + if (ux500_pm_other_cpu_wfi()) + break; + + if (ux500_pm_gic_pending_interrupt()) + return -1; + + if (atomic_read(&idle_cpus_counter) < num_online_cpus()) + return CI_WFI; + } + + power_state_req = power_state_active_is_enabled() || + prcmu_is_ac_wake_requested(); + + sleep_time = get_remaining_sleep_time(); + + /* + * Never go deeper than the governor recommends even though it might be + * possible from a scheduled wake up point of view + */ + max_depth = ux500_ci_dbg_deepest_state(); + + for_each_online_cpu(cpu) { + if (max_depth > per_cpu(cpu_state, cpu)->gov_cstate) + max_depth = per_cpu(cpu_state, cpu)->gov_cstate; + } + + for (i = max_depth; i > 0; i--) { + + if (sleep_time <= cstates[i].threshold) + continue; + + if (cstates[i].APE == APE_OFF) { + /* This state says APE should be off */ + if (power_state_req || + ux500_ci_dbg_force_ape_on()) + continue; + } + + /* OK state */ + break; + } + + return max(CI_WFI, i); + +} + +static void enter_sleep_shallow(struct cpu_state *state, ktime_t t1) +{ + int this_cpu = smp_processor_id(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu); + + switch (cstates[state->gov_cstate].ARM) { + case ARM_OFF: + context_varm_save_core(); + context_save_cpu_registers(); + /* fall through */ + case ARM_RET: + ux500_ci_dbg_log(CI_WFI, t1); + context_save_to_sram_and_wfi(false); + if (cstates[state->gov_cstate].ARM == ARM_OFF) + context_restore_cpu_registers(); + break; + case ARM_ON: + ux500_ci_dbg_log(CI_WFI, t1); + __asm__ __volatile__ + ("dsb\n\t" "wfi\n\t" : : : "memory"); + break; + default: + break; + } +} + +static int enter_sleep(struct cpuidle_device *dev, + struct cpuidle_state *ci_state) +{ + ktime_t t1, t2, t3; + ktime_t sleep_time; + s64 diff; + int ret; + int target; + struct cpu_state *state; + unsigned long iflags; + u32 divps_rate; + bool slept_well = false; + bool always_on_timer_migrated = false; + int this_cpu = smp_processor_id(); + + local_irq_disable(); + + t1 = ktime_get(); /* Time now */ + + state = per_cpu(cpu_state, smp_processor_id()); + + /* Retrive the cstate that the governor recommends for this CPU */ + state->gov_cstate = (int) cpuidle_get_statedata(ci_state); + + /* Save scheduled wake up for this cpu */ + spin_lock_irqsave(&cpuidle_lock, iflags); + state->sched_wake_up = ktime_add(t1, tick_nohz_get_sleep_length()); + spin_unlock_irqrestore(&cpuidle_lock, iflags); + + atomic_inc(&idle_cpus_counter); + + /* + * Determine sleep state considering both CPUs and + * shared resources like e.g. VAPE + */ + target = determine_sleep_state(); + if (target < 0) { + /* "target" will be last_state in the cpuidle framework */ + goto exit_fast; + } + + if (cstates[target].ARM == ARM_ON) { + /* Handle first cpu to enter sleep state */ + always_on_timer_migrated = true; + enter_sleep_shallow(state, t1); + t3 = ktime_get(); + slept_well = true; + goto exit; + } + + /* Decouple GIC from the interrupt bus */ + ux500_pm_gic_decouple(); + + if (!ux500_pm_other_cpu_wfi()) + /* Other CPU was not in WFI => abort */ + goto exit; + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu); + + always_on_timer_migrated = true; + + /* + * Check if we have a pending interrupt or if sleep + * state has changed after GIC has been frozen + */ + if (ux500_pm_gic_pending_interrupt()) + goto exit; + + if (target != determine_sleep_state()) + /* Sleep state has changed => abort */ + goto exit; + + /* Copy GIC interrupt settings to PRCMU interrupt settings */ + ux500_pm_prcmu_copy_gic_settings(); + + /* Clean the cache before slowing down cpu frequency */ + if (cstates[target].ARM == ARM_OFF) + context_clean_l1_cache_all(); + + divps_rate = ux500_pm_arm_on_ext_clk(cstates[target].ARM_PLL); + + if (ux500_pm_prcmu_pending_interrupt()) { + /* An interrupt found => abort */ + ux500_pm_arm_on_arm_pll(divps_rate); + goto exit; + } + + /* No PRCMU interrupt was pending => continue the sleeping stages */ + + if (cstates[target].APE == APE_OFF) { + /* We are going to sleep or deep sleep => prepare for it */ + + /* Program the only timer that is available when APE is off */ + clockevents_set_mode(&u8500_rtt_clkevt, + CLOCK_EVT_MODE_ONESHOT); + + sleep_time = ktime_set(0, get_remaining_sleep_time() * 1000); + + if (cstates[target].UL_PLL == UL_PLL_OFF) { + ktime_t ulpll_sleep = ktime_set(0, + UL_PLL_START_UP_LATENCY * 1000); + /* Compensate for ULPLL start up time */ + sleep_time = ktime_sub(sleep_time, ulpll_sleep); + + /* + * Not checking for negative sleep time since + * determine_sleep_state has already checked that + * there is enough time. + */ + } + + clockevents_program_event(&u8500_rtt_clkevt, + sleep_time, + time_zero); + + context_vape_save(); + + ux500_ci_dbg_console_handle_ape_suspend(); + ux500_pm_prcmu_set_ioforce(true); + + spin_lock_irqsave(&cpuidle_lock, iflags); + restore_ape = true; + spin_unlock_irqrestore(&cpuidle_lock, iflags); + } + + if (cstates[target].ARM == ARM_OFF) { + /* Save gic settings */ + context_varm_save_common(); + + context_varm_save_core(); + + spin_lock_irqsave(&cpuidle_lock, iflags); + restore_arm = true; + spin_unlock_irqrestore(&cpuidle_lock, iflags); + context_save_cpu_registers(); + } + + /* TODO: To use desc as debug print might be a bad idea */ + ux500_ci_dbg_msg(cstates[target].desc); + + /* + * Due to we have only 100us between requesting a + * powerstate and wfi, we clean the cache before as + * well to assure the final cache clean before wfi + * has as little as possible to do. + */ + if (cstates[target].ARM == ARM_OFF) + context_clean_l1_cache_all(); + + ux500_ci_dbg_log(target, t1); + + prcmu_set_power_state(cstates[target].pwrst, + cstates[target].UL_PLL, + /* Is actually the AP PLL */ + cstates[target].UL_PLL); + /* + * If deepsleep/deepidle, Save return address to SRAM and set + * this CPU in WFI. This is last core to enter sleep, so we need to + * clean both L2 and L1 caches + */ + + context_save_to_sram_and_wfi(cstates[target].ARM == ARM_OFF); + + t3 = ktime_get(); + + /* The PRCMU restores ARM PLL and recouples the GIC */ + if (cstates[target].ARM == ARM_OFF) + context_restore_cpu_registers(); + + slept_well = true; +exit: + if (!slept_well) + /* Recouple GIC with the interrupt bus */ + ux500_pm_gic_recouple(); + + restore_sequence(state, always_on_timer_migrated); + +exit_fast: + + if (target < 0) + target = CI_RUNNING; + + spin_lock_irqsave(&cpuidle_lock, iflags); + /* Remove wake up time i.e. set wake up far ahead */ + state->sched_wake_up = ktime_add_us(state->sched_wake_up, + 1000000000); /* 16 minutes ahead */ + smp_wmb(); + spin_unlock_irqrestore(&cpuidle_lock, iflags); + + atomic_dec(&idle_cpus_counter); + + /* + * We might have chosen another state than what the + * governor recommended + */ + if (target != state->gov_cstate) + /* Update last state pointer used by CPUIDLE subsystem */ + dev->last_state = &(dev->states[target]); + + t2 = ktime_get(); + diff = ktime_to_us(ktime_sub(t2, t1)); + if (diff > INT_MAX) + diff = INT_MAX; + + ret = (int)diff; + + ux500_ci_dbg_console_check_uart(); + if (slept_well) + ux500_ci_dbg_wake_leave(target, t3); + + ux500_ci_dbg_log(CI_RUNNING, t2); + + local_irq_enable(); + + ux500_ci_dbg_console(); + + return ret; +} + +static int init_cstates(int cpu, struct cpu_state *state) +{ + int i; + struct cpuidle_state *ci_state; + struct cpuidle_device *dev; + + dev = &state->dev; + dev->cpu = cpu; + + for (i = 0; i < ARRAY_SIZE(cstates); i++) { + + ci_state = &dev->states[i]; + + cpuidle_set_statedata(ci_state, (void *)i); + + ci_state->exit_latency = cstates[i].exit_latency; + ci_state->target_residency = cstates[i].threshold; + ci_state->flags = cstates[i].flags; + ci_state->enter = enter_sleep; + ci_state->power_usage = cstates[i].power_usage; + snprintf(ci_state->name, CPUIDLE_NAME_LEN, "C%d", i); + strncpy(ci_state->desc, cstates[i].desc, CPUIDLE_DESC_LEN); + } + + dev->state_count = ARRAY_SIZE(cstates); + + dev->safe_state = &dev->states[0]; /* Currently not used */ + + return cpuidle_register_device(dev); +} + +struct cpuidle_driver cpuidle_drv = { + .name = "cpuidle_driver", + .owner = THIS_MODULE, +}; + +static int __init cpuidle_driver_init(void) +{ + int res = -ENODEV; + int cpu; + + if (ux500_is_svp()) + goto out; + + /* Zero time used on a few places */ + time_zero = ktime_set(0, 0); + + /* Configure wake up reasons */ + prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | + PRCMU_WAKEUP(ABB)); + + ux500_ci_dbg_init(); + + for_each_possible_cpu(cpu) + per_cpu(cpu_state, cpu) = kzalloc(sizeof(struct cpu_state), + GFP_KERNEL); + + res = cpuidle_register_driver(&cpuidle_drv); + if (res) + goto out; + + for_each_possible_cpu(cpu) { + res = init_cstates(cpu, per_cpu(cpu_state, cpu)); + if (res) + goto out; + pr_info("cpuidle: initiated for CPU%d.\n", cpu); + } + return 0; +out: + pr_err("cpuidle: initialization failed.\n"); + return res; +} + +static void __exit cpuidle_driver_exit(void) +{ + int cpu; + struct cpuidle_device *dev; + + ux500_ci_dbg_remove(); + + for_each_possible_cpu(cpu) { + dev = &per_cpu(cpu_state, cpu)->dev; + cpuidle_unregister_device(dev); + } + + for_each_possible_cpu(cpu) + kfree(per_cpu(cpu_state, cpu)); + + cpuidle_unregister_driver(&cpuidle_drv); +} + +module_init(cpuidle_driver_init); +module_exit(cpuidle_driver_exit); + +MODULE_DESCRIPTION("U8500 cpuidle driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rickard Andersson <rickard.andersson@stericsson.com>"); diff --git a/arch/arm/mach-ux500/pm/cpuidle.h b/arch/arm/mach-ux500/pm/cpuidle.h new file mode 100644 index 00000000000..7baaf99d855 --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpuidle.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Rickard Andersson <rickard.andersson@stericsson.com> for + * ST-Ericsson. Loosly based on cpuidle.c by Sundar Iyer. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#ifndef __CPUIDLE_H +#define __CPUIDLE_H + +#include <linux/cpuidle.h> + +#include <mach/prcmu-fw-defs_v1.h> + +enum ARM { + ARM_OFF, + ARM_RET, + ARM_ON +}; + +enum APE { + APE_OFF, + APE_ON +}; + +enum ARM_PLL { + ARM_PLL_OFF = 0, + ARM_PLL_ON = 1 +}; + +enum UL_PLL { + UL_PLL_OFF, + UL_PLL_ON +}; + +enum ESRAM { + ESRAM_OFF, + ESRAM_RET +}; + +enum ci_pwrst { + CI_RUNNING = 0, + CI_WFI = 1, + CI_IDLE, + CI_SLEEP, + CI_DEEP_IDLE, + CI_DEEP_SLEEP, +}; + +struct cstate { + /* Required state of different hardwares */ + enum ARM ARM; + enum APE APE; + enum ARM_PLL ARM_PLL; + enum UL_PLL UL_PLL; + /* ESRAM = ESRAM_RET means that ESRAM context to be kept */ + enum ESRAM ESRAM; + + u32 enter_latency; + u32 exit_latency; + u32 power_usage; + u32 threshold; + u32 flags; + enum ap_pwrst_trans pwrst; + + /* Only used for debugging purpose */ + enum ci_pwrst state; + char desc[CPUIDLE_DESC_LEN]; +}; + +struct cstate *ux500_ci_get_cstates(int *len); + +#ifdef CONFIG_U8500_CPUIDLE +void ux500_cpuidle_plug(int cpu); +void ux500_cpuidle_unplug(int cpu); +#else +static inline void ux500_cpuidle_plug(int cpu) +{ +} + +static inline void ux500_cpuidle_unplug(int cpu) +{ +} +#endif + +#endif diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.c b/arch/arm/mach-ux500/pm/cpuidle_dbg.c new file mode 100644 index 00000000000..c451696fc6c --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpuidle_dbg.c @@ -0,0 +1,699 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Rickard Andersson <rickard.andersson@stericsson.com>, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + */ + +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/amba/serial.h> + +#include <plat/gpio.h> +#include <asm/hardware/gic.h> + +#include "cpuidle.h" +#include "pm.h" + +#define DBG_BUF_SIZE 5000 +#define APE_ON_TIMER_INTERVAL 5 /* Seconds */ + +#define UART_RX_GPIO_PIN_MASK (1 << (CONFIG_UX500_CONSOLE_UART_GPIO_PIN % 32)) + +#define UART011_MIS_RTIS (1 << 6) /* receive timeout interrupt status */ +#define UART011_MIS_RXIS (1 << 4) /* receive interrupt status */ +#define UART011_MIS 0x40 /* Masked interrupt status register */ + +struct state_history_state { + u32 counter; + ktime_t time; + + u32 enter_latency_count; + ktime_t enter_latency_sum; + ktime_t enter_latency_min; + ktime_t enter_latency_max; + + u32 exit_latency_count; + ktime_t exit_latency_sum; + ktime_t exit_latency_min; + ktime_t exit_latency_max; +}; + +struct state_history { + ktime_t start; + u32 state; + struct state_history_state *states; +}; +static DEFINE_PER_CPU(struct state_history, *state_history); + +static struct delayed_work cpuidle_work; +static u32 dbg_console_enable = 1; +static void __iomem *uart_base; +static struct clk *uart_clk; + +/* Blocks ApSleep and ApDeepSleep */ +static bool force_APE_on; +static bool reset_timer; +static int deepest_allowed_state = CONFIG_U8500_CPUIDLE_DEEPEST_STATE; +static u32 measure_latency; + +static struct cstate *cstates; +static int cstates_len; +static DEFINE_SPINLOCK(dbg_lock); + +#ifdef U8500_CPUIDLE_EXTRA_DBG +void ux500_ci_dbg_msg(char *dbg_string) +{ + static char dbg_buf[DBG_BUF_SIZE]; + static int index; /* protected by dbg_lock */ + int str_len; + int smp_no_len; + int head_len; + unsigned long flags; + static const char * const smp_no_str = "\n %d:"; + static const char * const head_str = ":HEAD->"; + + spin_lock_irqsave(&dbg_lock, flags); + + str_len = strlen(dbg_string); + smp_no_len = strlen(smp_no_str); + head_len = strlen(head_str); + + if (index > head_len) + /* Remove last head printing */ + index -= head_len; + + if ((index + str_len + smp_no_len + head_len) > DBG_BUF_SIZE) + index = 0; /* Non perfect wrapping... */ + + sprintf(&dbg_buf[index], smp_no_str, smp_processor_id()); + index += smp_no_len; + + strcpy(&dbg_buf[index], dbg_string); + index += str_len; + + strcpy(&dbg_buf[index], head_str); + index += head_len; + + spin_unlock_irqrestore(&dbg_lock, flags); +} +#endif + +bool ux500_ci_dbg_force_ape_on(void) +{ + clk_enable(uart_clk); + if (readw(uart_base + UART01x_FR) & UART01x_FR_BUSY) { + clk_disable(uart_clk); + return true; + } + clk_disable(uart_clk); + + return force_APE_on; +} + +int ux500_ci_dbg_deepest_state(void) +{ + return deepest_allowed_state; +} + +void ux500_ci_dbg_console_handle_ape_suspend(void) +{ + if (!dbg_console_enable) + return; + + set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 1); + set_irq_type(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), + IRQ_TYPE_EDGE_BOTH); +} + +void ux500_ci_dbg_console_handle_ape_resume(void) +{ + unsigned long flags; + u32 WKS_reg_value; + + if (!dbg_console_enable) + return; + + WKS_reg_value = ux500_pm_gpio_read_wake_up_status(0); + + if (WKS_reg_value & UART_RX_GPIO_PIN_MASK) { + spin_lock_irqsave(&dbg_lock, flags); + reset_timer = true; + spin_unlock_irqrestore(&dbg_lock, flags); + } + set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 0); + +} + +void ux500_ci_dbg_console_check_uart(void) +{ + unsigned long flags; + u32 status; + + if (!dbg_console_enable) + return; + + clk_enable(uart_clk); + spin_lock_irqsave(&dbg_lock, flags); + status = readw(uart_base + UART011_MIS); + + if (status & (UART011_MIS_RTIS | UART011_MIS_RXIS)) + reset_timer = true; + + spin_unlock_irqrestore(&dbg_lock, flags); + clk_disable(uart_clk); +} + +void ux500_ci_dbg_console(void) +{ + unsigned long flags; + + if (!dbg_console_enable) + return; + + spin_lock_irqsave(&dbg_lock, flags); + if (reset_timer) { + reset_timer = false; + spin_unlock_irqrestore(&dbg_lock, flags); + + cancel_delayed_work(&cpuidle_work); + force_APE_on = true; + schedule_delayed_work(&cpuidle_work, + msecs_to_jiffies(APE_ON_TIMER_INTERVAL * + 1000)); + } else { + spin_unlock_irqrestore(&dbg_lock, flags); + } +} + + +static void dbg_cpuidle_work_function(struct work_struct *work) +{ + force_APE_on = false; +} + +static void store_latency(u32 *count, + ktime_t d, + ktime_t *sum, + ktime_t *min, + ktime_t *max, + bool lock) +{ + unsigned long flags; + + if (lock) + spin_lock_irqsave(&dbg_lock, flags); + + (*count)++; + (*sum) = ktime_add((*sum), d); + + if (ktime_to_us(d) > ktime_to_us(*max)) + (*max) = d; + + if (ktime_to_us(d) < ktime_to_us((*min))) + (*min) = d; + + if (lock) + spin_unlock_irqrestore(&dbg_lock, flags); +} + +void ux500_ci_dbg_wake_leave(enum ci_pwrst pstate, ktime_t t) +{ + struct state_history *sh; + + if (pstate < CI_IDLE || !measure_latency) + return; + + sh = per_cpu(state_history, smp_processor_id()); + + store_latency(&sh->states[pstate].exit_latency_count, + ktime_sub(ktime_get(), t), + &sh->states[pstate].exit_latency_sum, + &sh->states[pstate].exit_latency_min, + &sh->states[pstate].exit_latency_max, + true); +} + +static void state_record_time(struct state_history *sh, enum ci_pwrst pstate, + ktime_t now, ktime_t start, bool latency) +{ + ktime_t dtime; + + dtime = ktime_sub(now, sh->start); + sh->states[sh->state].time = ktime_add(sh->states[sh->state].time, + dtime); + + sh->start = now; + sh->state = pstate; + + if (latency && pstate != CI_RUNNING && measure_latency) + store_latency(&sh->states[sh->state].enter_latency_count, + ktime_sub(now, start), + &sh->states[sh->state].enter_latency_sum, + &sh->states[sh->state].enter_latency_min, + &sh->states[sh->state].enter_latency_max, + false); + + sh->states[sh->state].counter++; +} + +void ux500_ci_dbg_log(enum ci_pwrst pstate, ktime_t enter_time) +{ + int i; + ktime_t now; + + unsigned long flags; + struct state_history *sh; + struct state_history *sh_other; + int this_cpu; + + this_cpu = smp_processor_id(); + + now = ktime_get(); + + sh = per_cpu(state_history, this_cpu); + + spin_lock_irqsave(&dbg_lock, flags); + + /* + * Check if current state is just a repeat of + * the state we're already in, then just quit. + */ + if (pstate == sh->state) + goto done; + + state_record_time(sh, pstate, now, enter_time, true); + + /* + * Update other cpus, (this_cpu = A, other cpus = B) if: + * - A = running and B != WFI | running: Set B to WFI + * - A = WFI and then B must be running: No changes + * - A = !WFI && !RUNNING and then B must be WFI: B sets to A + */ + + if (sh->state == CI_WFI) + goto done; + + for_each_possible_cpu(i) { + + if (this_cpu == i) + continue; + + sh_other = per_cpu(state_history, i); + + /* Same state, continue */ + if (sh_other->state == sh->state) + continue; + + if (pstate == CI_RUNNING && sh_other->state != CI_WFI) { + state_record_time(sh_other, CI_WFI, now, + enter_time, false); + continue; + } + /* + * This cpu is something else than running or wfi, both must be + * in the same state. + */ + state_record_time(sh_other, pstate, now, enter_time, true); + } +done: + spin_unlock_irqrestore(&dbg_lock, flags); +} + +static void state_history_reset(void) +{ + unsigned long flags; + unsigned int cpu; + int i; + struct state_history *sh; + + spin_lock_irqsave(&dbg_lock, flags); + + for_each_possible_cpu(cpu) { + sh = per_cpu(state_history, cpu); + for (i = 0; i <= cstates_len; i++) { + sh->states[i].counter = 0; + sh->states[i].time = ktime_set(0, 0); + + sh->states[i].enter_latency_count = 0; + sh->states[i].enter_latency_min = ktime_set(0, + 10000000); + sh->states[i].enter_latency_max = ktime_set(0, 0); + sh->states[i].enter_latency_sum = ktime_set(0, 0); + + sh->states[i].exit_latency_count = 0; + sh->states[i].exit_latency_min = ktime_set(0, + 10000000); + sh->states[i].exit_latency_max = ktime_set(0, 0); + sh->states[i].exit_latency_sum = ktime_set(0, 0); + } + + for (i = 0; i <= cstates_len; i++) + sh->start = ktime_get(); + sh->state = cstates_len; /* CI_RUNNING */ + } + spin_unlock_irqrestore(&dbg_lock, flags); +} + +static ssize_t set_deepest_state(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[32]; + ssize_t buf_size; + long unsigned int i; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (strict_strtoul(buf, 0, &i) != 0) + return buf_size; + + if (i > cstates_len - 1) + i = cstates_len - 1; + + if (i == 0) + i = 1; + + deepest_allowed_state = i; + + pr_debug("cpuidle: changed deepest allowed sleep state to %d.\n", + deepest_allowed_state); + + return buf_size; +} + +static int deepest_state_print(struct seq_file *s, void *p) +{ + seq_printf(s, "Deepest allowed sleep state is %d\n", + deepest_allowed_state); + + return 0; +} + +static ssize_t stats_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + + pr_info("\nreset\n"); + state_history_reset(); + return count; +} + +static int stats_print(struct seq_file *s, void *p) +{ + int cpu; + int i; + unsigned long flags; + struct state_history *sh; + ktime_t total; + s64 t_us; + s64 perc; + s64 total_us; + ktime_t init_time, zero_time; + + init_time = ktime_set(0, 10000000); + zero_time = ktime_set(0, 0); + + for_each_possible_cpu(cpu) { + sh = per_cpu(state_history, cpu); + spin_lock_irqsave(&dbg_lock, flags); + seq_printf(s, "\nCPU%d\n", cpu); + + total = ktime_set(0, 0); + + for (i = 0; i < cstates_len; i++) + total = ktime_add(total, sh->states[i].time); + + total_us = ktime_to_us(total); + do_div(total_us, 100); + + for (i = 0; i < cstates_len; i++) { + s64 avg_enter = 0; + s64 avg_exit = 0; + if (measure_latency) { + avg_enter = ktime_to_us(sh->states[i].enter_latency_sum); + avg_exit = ktime_to_us(sh->states[i].exit_latency_sum); + } + + t_us = ktime_to_us(sh->states[i].time); + perc = ktime_to_us(sh->states[i].time); + do_div(t_us, 1000); /* to ms */ + if (total_us) + do_div(perc, total_us); + if (sh->states[i].enter_latency_count && measure_latency) + do_div(avg_enter, sh->states[i].enter_latency_count); + + if (sh->states[i].exit_latency_count && measure_latency) + do_div(avg_exit, sh->states[i].exit_latency_count); + + seq_printf(s, "\n%d - %s: # %u in %d ms %d%%", + i, cstates[i].desc, + sh->states[i].counter, + (u32) t_us, (u32)perc); + if (i == CI_RUNNING) + continue; + + if (!ktime_equal(sh->states[i].enter_latency_min, + init_time) && measure_latency) { + if (ktime_equal(sh->states[i].enter_latency_min, + zero_time)) + seq_printf(s, " (enter: min < 30"); + else + seq_printf(s, " (enter: min %lld", + ktime_to_us(sh->states[i].enter_latency_min)); + + seq_printf(s, " avg %lld max %lld us)", + avg_enter, + ktime_to_us(sh->states[i].enter_latency_max)); + } + + if (!ktime_equal(sh->states[i].exit_latency_min, + init_time) && measure_latency) { + + if (ktime_equal(sh->states[i].exit_latency_min, + zero_time)) + seq_printf(s, " (exit: min < 30"); + else + seq_printf(s, " (exit: min %lld", + ktime_to_us(sh->states[i].exit_latency_min)); + + seq_printf(s, " avg %lld max %lld us)", + avg_exit, + ktime_to_us(sh->states[i].exit_latency_max)); + } + } + spin_unlock_irqrestore(&dbg_lock, flags); + } + seq_printf(s, "\n"); + return 0; +} + + +static int ap_family_show(struct seq_file *s, void *iter) +{ + int i; + u32 count = 0; + unsigned long flags; + struct state_history *sh; + + sh = per_cpu(state_history, 0); + spin_lock_irqsave(&dbg_lock, flags); + + for (i = 0 ; i < cstates_len; i++) { + if (cstates[i].state == (enum ci_pwrst)s->private) + count += sh->states[i].counter; + } + + seq_printf(s, "%u\n", count); + spin_unlock_irqrestore(&dbg_lock, flags); + + return 0; +} + +static int deepest_state_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, deepest_state_print, inode->i_private); +} + +static int stats_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, stats_print, inode->i_private); +} + + +static int ap_family_open(struct inode *inode, + struct file *file) +{ + return single_open(file, ap_family_show, inode->i_private); +} + +static const struct file_operations deepest_state_fops = { + .open = deepest_state_open_file, + .write = set_deepest_state, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations stats_fops = { + .open = stats_open_file, + .write = stats_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ap_family_fops = { + .open = ap_family_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static struct dentry *cpuidle_dir; + +static void setup_debugfs(void) +{ + cpuidle_dir = debugfs_create_dir("cpuidle", NULL); + if (IS_ERR_OR_NULL(cpuidle_dir)) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("deepest_state", + S_IWUGO | S_IRUGO, cpuidle_dir, + NULL, &deepest_state_fops))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("stats", + S_IRUGO, cpuidle_dir, NULL, + &stats_fops))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_bool("dbg_console_enable", + S_IWUGO | S_IRUGO, cpuidle_dir, + &dbg_console_enable))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_bool("measure_latency", + S_IWUGO | S_IRUGO, cpuidle_dir, + &measure_latency))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("ap_idle", S_IRUGO, + cpuidle_dir, + (void *)CI_IDLE, + &ap_family_fops))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("ap_sleep", S_IRUGO, + cpuidle_dir, + (void *)CI_SLEEP, + &ap_family_fops))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("ap_deepidle", S_IRUGO, + cpuidle_dir, + (void *)CI_DEEP_IDLE, + &ap_family_fops))) + goto fail; + + if (IS_ERR_OR_NULL(debugfs_create_file("ap_deepsleep", S_IRUGO, + cpuidle_dir, + (void *)CI_DEEP_SLEEP, + &ap_family_fops))) + goto fail; + + return; +fail: + debugfs_remove_recursive(cpuidle_dir); +} + +void ux500_ci_dbg_init(void) +{ + char clkname[10]; + int cpu; + + struct state_history *sh; + + cstates = ux500_ci_get_cstates(&cstates_len); + + for_each_possible_cpu(cpu) { + per_cpu(state_history, cpu) = kzalloc(sizeof(struct state_history), + GFP_KERNEL); + sh = per_cpu(state_history, cpu); + sh->states = kzalloc(sizeof(struct state_history_state) + * cstates_len, + GFP_KERNEL); + } + + state_history_reset(); + + for_each_possible_cpu(cpu) { + sh = per_cpu(state_history, cpu); + /* Only first CPU used during boot */ + if (cpu == 0) + sh->state = CI_RUNNING; + else + sh->state = CI_WFI; + } + + setup_debugfs(); + + /* Uart debug init */ + switch (CONFIG_UX500_DEBUG_UART) { + case 0: + uart_base = ioremap(U8500_UART0_BASE, SZ_4K); + break; + case 1: + uart_base = ioremap(U8500_UART1_BASE, SZ_4K); + break; + case 2: + uart_base = ioremap(U8500_UART2_BASE, SZ_4K); + break; + default: + uart_base = ioremap(U8500_UART2_BASE, SZ_4K); + break; + } + + snprintf(clkname, sizeof(clkname), "uart%d", CONFIG_UX500_DEBUG_UART); + uart_clk = clk_get_sys(clkname, NULL); + BUG_ON(IS_ERR(uart_clk)); + + INIT_DELAYED_WORK(&cpuidle_work, dbg_cpuidle_work_function); + +} + +void ux500_ci_dbg_remove(void) +{ + int cpu; + struct state_history *sh; + + debugfs_remove_recursive(cpuidle_dir); + + for_each_possible_cpu(cpu) { + sh = per_cpu(state_history, cpu); + kfree(sh->states); + kfree(sh); + } + + iounmap(uart_base); +} diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.h b/arch/arm/mach-ux500/pm/cpuidle_dbg.h new file mode 100644 index 00000000000..93df7528e6c --- /dev/null +++ b/arch/arm/mach-ux500/pm/cpuidle_dbg.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Rickard Andersson <rickard.andersson@stericsson.com> for ST-Ericsson + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + */ + +#ifndef CPUIDLE_DBG_H +#define CPUIDLE_DBG_H + +#ifdef CONFIG_U8500_CPUIDLE_DEBUG +void ux500_ci_dbg_init(void); +void ux500_ci_dbg_remove(void); + +void ux500_ci_dbg_log(enum ci_pwrst pstate, ktime_t enter_time); +void ux500_ci_dbg_wake_leave(enum ci_pwrst pstate, ktime_t t); + +bool ux500_ci_dbg_force_ape_on(void); +int ux500_ci_dbg_deepest_state(void); + +void ux500_ci_dbg_console(void); +void ux500_ci_dbg_console_check_uart(void); +void ux500_ci_dbg_console_handle_ape_resume(void); +void ux500_ci_dbg_console_handle_ape_suspend(void); + +#ifdef U8500_CPUIDLE_EXTRA_DBG +void ux500_ci_dbg_msg(char *dbg_string); +#else +static inline void ux500_ci_dbg_msg(char *dbg_string) { } +#endif + +#else + +static inline void ux500_ci_dbg_init(void) { } +static inline void ux500_ci_dbg_remove(void) { } + +static inline void ux500_ci_dbg_log(enum ci_pwrst pstate, + ktime_t enter_time) { } +static inline void ux500_ci_dbg_wake_leave(enum ci_pwrst pstate, ktime_t t) { } + +static inline bool ux500_ci_dbg_force_ape_on(void) +{ + return false; +} + +static inline int ux500_ci_dbg_deepest_state(void) +{ + /* This means no lower sleep state than ApIdle */ + return CONFIG_U8500_CPUIDLE_DEEPEST_STATE; +} + +static inline void ux500_ci_dbg_console(void) { } +static inline void ux500_ci_dbg_console_check_uart(void) { } +static inline void ux500_ci_dbg_console_handle_ape_resume(void) { } +static inline void ux500_ci_dbg_console_handle_ape_suspend(void) { } +static inline void ux500_ci_dbg_msg(char *dbg_string) { } + +#endif +#endif diff --git a/arch/arm/mach-ux500/pm/pm.c b/arch/arm/mach-ux500/pm/pm.c new file mode 100644 index 00000000000..1db45c8c0ae --- /dev/null +++ b/arch/arm/mach-ux500/pm/pm.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Rickard Andersson <rickard.andersson@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#include <linux/io.h> +#include <linux/percpu.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <asm/hardware/gic.h> + +#include <mach/hardware.h> +#include <mach/prcmu-regs.h> + +#define STABILIZATION_TIME 30 /* us */ + +#define PRCM_ARM_WFI_STANDBY_CPU0_WFI 0x8 +#define PRCM_ARM_WFI_STANDBY_CPU1_WFI 0x10 + +static u32 u8500_gpio_banks[] = {U8500_GPIOBANK0_BASE, + U8500_GPIOBANK1_BASE, + U8500_GPIOBANK2_BASE, + U8500_GPIOBANK3_BASE, + U8500_GPIOBANK4_BASE, + U8500_GPIOBANK5_BASE, + U8500_GPIOBANK6_BASE, + U8500_GPIOBANK7_BASE, + U8500_GPIOBANK8_BASE}; + +static u32 u5500_gpio_banks[] = {U5500_GPIOBANK0_BASE, + U5500_GPIOBANK1_BASE, + U5500_GPIOBANK2_BASE, + U5500_GPIOBANK3_BASE, + U5500_GPIOBANK4_BASE, + U5500_GPIOBANK5_BASE, + U5500_GPIOBANK6_BASE, + U5500_GPIOBANK7_BASE}; + +static u32 ux500_gpio_wks[ARRAY_SIZE(u8500_gpio_banks)]; +#ifdef ENABLE_ARM_FREQ_RAMP +/* + * Ramp down the ARM frequency in order to reduce voltage + * overshoot/undershoot + */ +int ux500_pm_arm_on_ext_clk(bool leave_arm_pll_on) +{ + u32 val; + int divps_rate; + + /* + * TODO: we should check that there is no ongoing + * OPP change because then our writings could collide with the PRCMU. + */ + + val = readl(PRCM_ARM_CHGCLKREQ); + + if (val & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) + return -EINVAL; + + val = readl(PRCM_ARM_PLLDIVPS); + + /* + * TODO: Investigate if ramp down should start + * from current frequency. + */ + if (cpu_is_u8500v20_or_later()) { + + /* + * Store the current rate value. Is needed if + * we need to restore the frequency + */ + divps_rate = val & PRCM_ARM_PLLDIVPS_ARM_BRM_RATE; + val &= ~PRCM_ARM_PLLDIVPS_ARM_BRM_RATE; + + /* Slow down the cpu's */ + if (divps_rate > 11) { + writel(val | 11, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate > 5) { + writel(val | 5, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate > 2) + writel(val | 2, PRCM_ARM_PLLDIVPS); + } else { + + divps_rate = val & PRCM_ARM_PLLDIVPS_MAX_MASK; + val &= ~PRCM_ARM_PLLDIVPS_MAX_MASK; + + /* Slow down the cpu's */ + if (divps_rate < 3) { + writel(val | 3, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate < 7) { + writel(val | 7, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate < 15) + writel(val | 15, PRCM_ARM_PLLDIVPS); + } + + /* switch to external clock */ + writel(readl(PRCM_ARM_CHGCLKREQ) | + PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ, + PRCM_ARM_CHGCLKREQ); + + val = readl(PRCM_PLLARM_ENABLE); + + if (leave_arm_pll_on) + /* Leave ARM PLL on */ + writel(val & (~PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON), + PRCM_PLLARM_ENABLE); + else + /* Stop ARM PLL */ + writel(val & (~PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE), + PRCM_PLLARM_ENABLE); + return divps_rate; +} +#else +inline int ux500_pm_arm_on_ext_clk(bool leave_arm_pll_on) +{ + return 0; +} +#endif + +#ifdef ENABLE_ARM_FREQ_RAMP +void ux500_pm_arm_on_arm_pll(int divps_rate) +{ + u32 pll_arm; + u32 clk_req; + u32 val; + + if (divps_rate < 0) + return; + + clk_req = readl(PRCM_ARM_CHGCLKREQ); + + /* Return, if not running on external pll */ + if (!(clk_req & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ)) + return; + + pll_arm = readl(PRCM_PLLARM_ENABLE); + + if (pll_arm & PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE) { + /* ARM PLL is still on, set "counton" bit */ + writel(pll_arm | PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON, + PRCM_PLLARM_ENABLE); + } else { + /* ARM PLL was stopped => turn on */ + writel(pll_arm | PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE, + PRCM_PLLARM_ENABLE); + + /* Wait for PLL to lock */ + while (!(readl(PRCM_PLLARM_LOCKP) & + PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3)) + cpu_relax(); + } + + writel(clk_req & ~PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ, + PRCM_ARM_CHGCLKREQ); + + val = readl(PRCM_ARM_PLLDIVPS); + + if (cpu_is_u8500v20_or_later()) { + val &= ~PRCM_ARM_PLLDIVPS_ARM_BRM_RATE; + + /* Ramp up the ARM PLL */ + if (divps_rate >= 2) { + writel(val | 2, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate >= 5) { + writel(val | 5, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate >= 11) + writel(val | 11, PRCM_ARM_PLLDIVPS); + } else { + val &= ~PRCM_ARM_PLLDIVPS_MAX_MASK; + /* Ramp up the ARM PLL */ + if (divps_rate <= 15) { + writel(val | 15, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate <= 7) { + writel(val | 7, PRCM_ARM_PLLDIVPS); + /* Wait for voltage to stabilize */ + udelay(STABILIZATION_TIME); + } + if (divps_rate <= 3) + writel(val | 3, PRCM_ARM_PLLDIVPS); + } +} +#else +inline void ux500_pm_arm_on_arm_pll(int divps_rate) +{ +} +#endif + +/* Decouple GIC from the interrupt bus */ +void ux500_pm_gic_decouple(void) +{ + writel(readl(PRCM_A9_MASK_REQ) | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, + PRCM_A9_MASK_REQ); + + while (!readl(PRCM_A9_MASK_REQ)) + cpu_relax(); + + /* TODO: Use the ack bit when possible */ +} + +/* Recouple GIC with the interrupt bus */ +void ux500_pm_gic_recouple(void) +{ + writel((readl(PRCM_A9_MASK_REQ) & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ), + PRCM_A9_MASK_REQ); + + /* TODO: Use the ack bit when possible */ +} + +#define GIC_NUMBER_REGS 5 +bool ux500_pm_gic_pending_interrupt(void) +{ + u32 pr; /* Pending register */ + u32 er; /* Enable register */ + int i; + + /* 5 registers. STI & PPI not skipped */ + for (i = 0; i < GIC_NUMBER_REGS; i++) { + + pr = readl(__io_address(U8500_GIC_DIST_BASE) + + GIC_DIST_PENDING_SET + i * 4); + er = readl(__io_address(U8500_GIC_DIST_BASE) + + GIC_DIST_ENABLE_SET + i * 4); + + if (pr & er) + return true; /* There is a pending interrupt */ + + } + + return false; +} + +#define GIC_NUMBER_SPI_REGS 4 +bool ux500_pm_prcmu_pending_interrupt(void) +{ + u32 it; + u32 im; + int i; + + for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* There are 4 registers */ + + it = readl(PRCM_ARMITVAL31TO0 + i * 4); + im = readl(PRCM_ARMITMSK31TO0 + i * 4); + + if (it & im) + return true; /* There is a pending interrupt */ + } + + return false; +} + +void ux500_pm_prcmu_set_ioforce(bool enable) +{ + if (enable) + writel(readl(PRCM_IOCR) | PRCM_IOCR_IOFORCE, PRCM_IOCR); + else + writel(readl(PRCM_IOCR) & ~PRCM_IOCR_IOFORCE, PRCM_IOCR); +} + +void ux500_pm_prcmu_copy_gic_settings(void) +{ + u32 er; /* Enable register */ + int i; + + for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* 4*32 SPI interrupts */ + /* +1 due to skip STI and PPI */ + er = readl(IO_ADDRESS(U8500_GIC_DIST_BASE) + + GIC_DIST_ENABLE_SET + (i + 1) * 4); + writel(er, PRCM_ARMITMSK31TO0 + i * 4); + } +} + +void ux500_pm_gpio_save_wake_up_status(void) +{ + int num_banks; + u32 *banks; + int i; + + if (cpu_is_u5500()) { + num_banks = ARRAY_SIZE(u5500_gpio_banks); + banks = u5500_gpio_banks; + } else { + num_banks = ARRAY_SIZE(u8500_gpio_banks); + banks = u8500_gpio_banks; + } + + nmk_gpio_clocks_enable(); + + for (i = 0; i < num_banks; i++) + ux500_gpio_wks[i] = readl(IO_ADDRESS(banks[i]) + NMK_GPIO_WKS); + + nmk_gpio_clocks_disable(); +} + +u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_num) +{ + if (WARN_ON(cpu_is_u5500() && bank_num >= + ARRAY_SIZE(u5500_gpio_banks))) + return 0; + + if (WARN_ON(cpu_is_u8500() && bank_num >= + ARRAY_SIZE(u8500_gpio_banks))) + return 0; + + return ux500_gpio_wks[bank_num]; +} + +/* Check if the other CPU is in WFI */ +bool ux500_pm_other_cpu_wfi(void) +{ + if (smp_processor_id()) { + /* We are CPU 1 => check if CPU0 is in WFI */ + if (readl(PRCM_ARM_WFI_STANDBY) & + PRCM_ARM_WFI_STANDBY_CPU0_WFI) + return true; + } else { + /* We are CPU 0 => check if CPU1 is in WFI */ + if (readl(PRCM_ARM_WFI_STANDBY) & + PRCM_ARM_WFI_STANDBY_CPU1_WFI) + return true; + } + + return false; +} diff --git a/arch/arm/mach-ux500/pm/pm.h b/arch/arm/mach-ux500/pm/pm.h new file mode 100644 index 00000000000..e8f67183682 --- /dev/null +++ b/arch/arm/mach-ux500/pm/pm.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Rickard Andersson <rickard.andersson@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2 + * + */ + +#ifndef PM_COMMON_H +#define PM_COMMON_H + +#ifdef CONFIG_PM +/** + * ux500_pm_arm_on_ext_clk() + * + * @leave_arm_pll_on: True, if leave the ARM PLL on. + * + * returns divps_rate, used as input for ux500_pm_arm_on_arm_pll + * or -EINVAL if already running on external clock. + */ +int ux500_pm_arm_on_ext_clk(bool leave_arm_pll_on); + +/** + * ux500_pm_arm_on_arm_pll() + * + * @divps_rate: Rate provided by ux500_pm_arm_on_ext_clk + * + * Restores the previous arm pll settings. + */ +void ux500_pm_arm_on_arm_pll(int divps_rate); + +/** + * ux500_pm_gic_decouple() + * + * Decouple GIC from the interrupt bus. + */ +void ux500_pm_gic_decouple(void); + +/** + * ux500_pm_gic_recouple() + * + * Recouple GIC with the interrupt bus. + */ +void ux500_pm_gic_recouple(void); + +/** + * ux500_pm_gic_pending_interrupt() + * + * returns true, if there are pending interrupts. + */ +bool ux500_pm_gic_pending_interrupt(void); + +/** + * ux500_pm_prcmu_pending_interrupt() + * + * returns true, if there are pending interrupts. + */ +bool ux500_pm_prcmu_pending_interrupt(void); + +/** + * ux500_pm_prcmu_set_ioforce() + * + * @enable: Enable/disable + * + * Enable/disable the gpio-ring + */ +void ux500_pm_prcmu_set_ioforce(bool enable); + +/** + * ux500_pm_prcmu_copy_gic_settings() + * + * This function copies all the gic interrupt settings to the prcmu. + * This is needed for the system to catch interrupts in ApIdle + */ +void ux500_pm_prcmu_copy_gic_settings(void); + +/** + * ux500_pm_gpio_save_wake_up_status() + * + * This function is called when the prcmu has woken the ARM + * but before ioforce is disabled. + */ +void ux500_pm_gpio_save_wake_up_status(void); + +/** + * ux500_pm_gpio_read_wake_up_status() + * + * @bank_number: The gpio bank. + * + * Returns the WKS register settings for given bank number. + * The WKS register is cleared when ioforce is released therefore + * this function is needed. + */ +u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_number); + +/** + * ux500_pm_other_cpu_wfi() + * + * Returns true if the other CPU is in WFI. + */ +bool ux500_pm_other_cpu_wfi(void); + +#else +u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_number) +{ + return 0; +} +#endif + +#endif diff --git a/arch/arm/mach-ux500/pm/runtime.c b/arch/arm/mach-ux500/pm/runtime.c new file mode 100644 index 00000000000..cb6801b04b1 --- /dev/null +++ b/arch/arm/mach-ux500/pm/runtime.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Rabin Vincent <rabin.vincent@stericsson> for ST-Ericsson + * + * Based on: + * Runtime PM support code for SuperH Mobile ARM + * Copyright (C) 2009-2010 Magnus Damm + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> +#include <linux/clk.h> +#include <plat/pincfg.h> +#include <mach/regulator.h> + +#include "../pins.h" + +#ifdef CONFIG_PM_RUNTIME +#define BIT_ONCE 0 +#define BIT_ACTIVE 1 +#define BIT_ENABLED 2 + +struct pm_runtime_data { + unsigned long flags; + struct ux500_regulator *regulator; + struct ux500_pins *pins; +}; + +static void __devres_release(struct device *dev, void *res) +{ + struct pm_runtime_data *prd = res; + + dev_dbg(dev, "__devres_release()\n"); + + if (test_bit(BIT_ENABLED, &prd->flags)) { + if (prd->pins) + ux500_pins_disable(prd->pins); + if (prd->regulator) + ux500_regulator_atomic_disable(prd->regulator); + } + + if (test_bit(BIT_ACTIVE, &prd->flags)) { + if (prd->pins) + ux500_pins_put(prd->pins); + if (prd->regulator) + ux500_regulator_put(prd->regulator); + } +} + +static struct pm_runtime_data *__to_prd(struct device *dev) +{ + return devres_find(dev, __devres_release, NULL, NULL); +} + +static void platform_pm_runtime_init(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) { + prd->pins = ux500_pins_get(dev_name(dev)); + + prd->regulator = ux500_regulator_get(dev); + if (IS_ERR(prd->regulator)) + prd->regulator = NULL; + + if (prd->pins || prd->regulator) { + dev_info(dev, "managed by runtime pm: %s%s\n", + prd->pins ? "pins " : "", + prd->regulator ? "regulator " : ""); + + set_bit(BIT_ACTIVE, &prd->flags); + } + } +} + +static void platform_pm_runtime_bug(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) + dev_err(dev, "runtime pm suspend before resume\n"); +} + +static int ux500_pd_runtime_suspend(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_vdbg(dev, "%s()\n", __func__); + + platform_pm_runtime_bug(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + if (prd->pins) + ux500_pins_disable(prd->pins); + + if (prd->regulator) + ux500_regulator_atomic_disable(prd->regulator); + + clear_bit(BIT_ENABLED, &prd->flags); + } + + return 0; +} + +static int ux500_pd_runtime_resume(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_vdbg(dev, "%s()\n", __func__); + + platform_pm_runtime_init(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + if (prd->pins) + ux500_pins_enable(prd->pins); + + if (prd->regulator) + ux500_regulator_atomic_enable(prd->regulator); + + set_bit(BIT_ENABLED, &prd->flags); + } + + return 0; +} + +static int ux500_pd_suspend_noirq(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_vdbg(dev, "%s()\n", __func__); + + /* Only handle devices that use runtime pm */ + if (!prd || !test_bit(BIT_ONCE, &prd->flags)) + return 0; + + /* Already is runtime suspended? Nothing to do. */ + if (pm_runtime_suspended(dev)) + return 0; + + /* + * We get here only if the device was not runtime suspended for some + * reason. We still need to do the power save stuff when going into + * suspend, so force it here. + */ + return ux500_pd_runtime_suspend(dev); +} + +static int ux500_pd_resume_noirq(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_vdbg(dev, "%s()\n", __func__); + + /* Only handle devices that use runtime pm */ + if (!prd || !test_bit(BIT_ONCE, &prd->flags)) + return 0; + + /* + * Already was runtime suspended? No need to resume here, runtime + * resume will take care of it. + */ + if (pm_runtime_suspended(dev)) + return 0; + + /* + * We get here only if the device was not runtime suspended, + * but we forced it down in suspend_noirq above. Bring it + * up since pm-runtime thinks it is not suspended. + */ + return ux500_pd_runtime_resume(dev); +} + +static int ux500_pd_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct pm_runtime_data *prd; + + dev_dbg(dev, "%s() %ld !\n", __func__, action); + + if (action == BUS_NOTIFY_BIND_DRIVER) { + prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); + if (prd) + devres_add(dev, prd); + else + dev_err(dev, "unable to alloc memory for runtime pm\n"); + } + + return 0; +} + +#else /* CONFIG_PM_RUNTIME */ + +#define ux500_pd_suspend_noirq NULL +#define ux500_pd_resume_noirq NULL +#define ux500_pd_runtime_suspend NULL +#define ux500_pd_runtime_resume NULL + +static int ux500_pd_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ux500_regulator *regulator = NULL; + struct ux500_pins *pins = NULL; + struct device *dev = data; + const char *onoff = NULL; + + dev_dbg(dev, "%s() %ld !\n", __func__, action); + + switch (action) { + case BUS_NOTIFY_BIND_DRIVER: + pins = ux500_pins_get(dev_name(dev)); + if (pins) { + ux500_pins_enable(pins); + ux500_pins_put(pins); + } + + regulator = ux500_regulator_get(dev); + if (IS_ERR(regulator)) + regulator = NULL; + else { + ux500_regulator_atomic_enable(regulator); + ux500_regulator_put(regulator); + } + + onoff = "on"; + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + pins = ux500_pins_get(dev_name(dev)); + if (pins) { + ux500_pins_disable(pins); + ux500_pins_put(pins); + } + + regulator = ux500_regulator_get(dev); + if (IS_ERR(regulator)) + regulator = NULL; + else { + ux500_regulator_atomic_disable(regulator); + ux500_regulator_put(regulator); + } + + onoff = "off"; + break; + } + + if (pins || regulator) { + dev_info(dev, "runtime pm disabled, forced %s: %s%s\n", + onoff, + pins ? "pins " : "", + regulator ? "regulator " : ""); + } + + return 0; +} + +#endif /* CONFIG_PM_RUNTIME */ + +struct dev_power_domain ux500_dev_power_domain = { + .ops = { + .suspend_noirq = ux500_pd_suspend_noirq, + .resume_noirq = ux500_pd_resume_noirq, + .runtime_suspend = ux500_pd_runtime_suspend, + .runtime_resume = ux500_pd_runtime_resume, + }, +}; + +static struct notifier_block ux500_pd_platform_notifier = { + .notifier_call = ux500_pd_bus_notify, +}; + +static struct notifier_block ux500_pd_amba_notifier = { + .notifier_call = ux500_pd_bus_notify, +}; + +static int __init ux500_pm_runtime_platform_init(void) +{ + bus_register_notifier(&platform_bus_type, &ux500_pd_platform_notifier); + return 0; +} +core_initcall(ux500_pm_runtime_platform_init); + +/* + * The amba bus itself gets registered in a core_initcall, so we can't use + * that. + */ +static int __init ux500_pm_runtime_amba_init(void) +{ + bus_register_notifier(&amba_bustype, &ux500_pd_amba_notifier); + return 0; +} +arch_initcall(ux500_pm_runtime_amba_init); diff --git a/arch/arm/mach-ux500/pm/suspend.c b/arch/arm/mach-ux500/pm/suspend.c new file mode 100644 index 00000000000..4ca62da3842 --- /dev/null +++ b/arch/arm/mach-ux500/pm/suspend.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Authors: Rickard Andersson <rickard.andersson@stericsson.com>, + * Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * + */ + +#include <linux/suspend.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/regulator/ab8500-debug.h> + +#include <mach/prcmu-fw-api.h> +#include <mach/prcmu-regs.h> + +#include "context.h" +#include "pm.h" +#include "suspend_dbg.h" + +static void (*pins_suspend_force)(void); +static void (*pins_suspend_force_mux)(void); + +void suspend_set_pins_force_fn(void (*force)(void), void (*force_mux)(void)) +{ + pins_suspend_force = force; + pins_suspend_force_mux = force_mux; +} + +static atomic_t block_sleep = ATOMIC_INIT(0); + +void suspend_block_sleep(void) +{ + atomic_inc(&block_sleep); +} + +void suspend_unblock_sleep(void) +{ + atomic_dec(&block_sleep); +} + +static bool sleep_is_blocked(void) +{ + return (atomic_read(&block_sleep) != 0); +} + +static int suspend(bool do_deepsleep) +{ + bool pins_force = pins_suspend_force_mux && pins_suspend_force; + int ret = 0; + u32 divps_rate; + + if (sleep_is_blocked()) { + pr_info("suspend/resume: interrupted by modem.\n"); + return -EBUSY; + } + + nmk_gpio_clocks_enable(); + + ux500_suspend_dbg_add_wake_on_uart(); + nmk_gpio_wakeups_suspend(); + + /* configure the prcm for a sleep wakeup */ + prcmu_enable_wakeups(PRCMU_WAKEUP(ABB)); + + context_vape_save(); + + if (pins_force) { + /* + * Save GPIO settings before applying power save + * settings + */ + context_gpio_save(); + + /* Apply GPIO power save mux settings */ + context_gpio_mux_safe_switch(true); + pins_suspend_force_mux(); + context_gpio_mux_safe_switch(false); + + /* Apply GPIO power save settings */ + pins_suspend_force(); + } + + ux500_pm_gic_decouple(); + + /* TODO: decouple gic should look at status bit.*/ + udelay(100); + + divps_rate = ux500_pm_arm_on_ext_clk(false); + + if (ux500_pm_gic_pending_interrupt()) { + pr_info("suspend/resume: pending interrupt\n"); + + ux500_pm_arm_on_arm_pll(divps_rate); + /* Recouple GIC with the interrupt bus */ + ux500_pm_gic_recouple(); + ret = -EBUSY; + + goto exit; + } + ux500_pm_prcmu_set_ioforce(true); + + if (do_deepsleep) { + context_varm_save_common(); + context_varm_save_core(); + context_save_cpu_registers(); + + /* + * Due to we have only 100us between requesting a powerstate + * and wfi, we clean the cache before as well to assure the + * final cache clean before wfi has as little as possible to + * do. + */ + context_clean_l1_cache_all(); + + (void) prcmu_set_power_state(PRCMU_AP_DEEP_SLEEP, + false, false); + context_save_to_sram_and_wfi(true); + + context_restore_cpu_registers(); + context_varm_restore_core(); + context_varm_restore_common(); + + } else { + + context_clean_l1_cache_all(); + (void) prcmu_set_power_state(APEXECUTE_TO_APSLEEP, + false, false); + dsb(); + __asm__ __volatile__("wfi\n\t" : : : "memory"); + } + + context_vape_restore(); + + /* If GPIO woke us up then save the pins that caused the wake up */ + ux500_pm_gpio_save_wake_up_status(); + + ux500_suspend_dbg_sleep_status(do_deepsleep); + + /* APE was turned off, restore IO ring */ + ux500_pm_prcmu_set_ioforce(false); + +exit: + if (pins_force) { + /* Restore gpio settings */ + context_gpio_mux_safe_switch(true); + context_gpio_restore_mux(); + context_gpio_mux_safe_switch(false); + context_gpio_restore(); + } + + /* This is what cpuidle wants */ + prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | + PRCMU_WAKEUP(ABB)); + + nmk_gpio_wakeups_resume(); + ux500_suspend_dbg_remove_wake_on_uart(); + + nmk_gpio_clocks_disable(); + + return ret; +} + +static int ux500_suspend_enter(suspend_state_t state) +{ + + if (ux500_suspend_enabled()) { + if (ux500_suspend_deepsleep_enabled() && + state == PM_SUSPEND_MEM) + return suspend(true); + if (ux500_suspend_sleep_enabled()) + return suspend(false); + /* For debugging, if Sleep and DeepSleep disabled, do Idle */ + prcmu_set_power_state(PRCMU_AP_IDLE, true, true); + } + + dsb(); + __asm__ __volatile__("wfi\n\t" : : : "memory"); + return 0; +} + +static int ux500_suspend_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; +} + +static int ux500_suspend_prepare_late(void) +{ + /* + * Below should be set to state OFF. Current workaround set state to + * RET since there is a problem with security saving data in esram + * which does not work during deep sleep. + * Once security is fixed below should be state OFF again to save 40uA. + */ + (void)prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); + ab8500_regulator_debug_force(); + + return 0; +} + +static void ux500_suspend_wake(void) +{ + ab8500_regulator_debug_restore(); + (void)prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); +} + +static struct platform_suspend_ops ux500_suspend_ops = { + .enter = ux500_suspend_enter, + .valid = ux500_suspend_valid, + .prepare_late = ux500_suspend_prepare_late, + .wake = ux500_suspend_wake, + .begin = ux500_suspend_dbg_begin, +}; + +static __init int ux500_suspend_init(void) +{ + ux500_suspend_dbg_init(); + suspend_set_ops(&ux500_suspend_ops); + return 0; +} + +device_initcall(ux500_suspend_init); diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.c b/arch/arm/mach-ux500/pm/suspend_dbg.c new file mode 100644 index 00000000000..fce77b5cf73 --- /dev/null +++ b/arch/arm/mach-ux500/pm/suspend_dbg.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Rickard Andersson <rickard.andersson@stericsson.com>, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/suspend.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> + +#define DEEP_SLEEP_OK 0xf6 +#define SLEEP_OK 0xf3 + +#define PRCMU_STATUS_REGISTER_V1 0x8015fe08 +#define PRCMU_STATUS_REGISTER_V2 0x801b8e08 + +static void __iomem *prcmu_status_reg; + +#ifdef CONFIG_UX500_SUSPEND_STANDBY +static u32 sleep_enabled = 1; +#else +static u32 sleep_enabled; +#endif + +#ifdef CONFIG_UX500_SUSPEND_MEM +static u32 deepsleep_enabled = 1; +#else +static u32 deepsleep_enabled; +#endif + +static u32 suspend_enabled = 1; + +static u32 deepsleeps_done; +static u32 deepsleeps_failed; +static u32 sleeps_done; +static u32 sleeps_failed; +static u32 suspend_count; + +#ifdef CONFIG_UX500_SUSPEND_DBG_WAKE_ON_UART +void ux500_suspend_dbg_add_wake_on_uart(void) +{ + set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 1); + set_irq_type(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), + IRQ_TYPE_EDGE_BOTH); +} + +void ux500_suspend_dbg_remove_wake_on_uart(void) +{ + set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 0); +} +#endif + +bool ux500_suspend_enabled(void) +{ + return suspend_enabled != 0; +} + +bool ux500_suspend_sleep_enabled(void) +{ + return sleep_enabled != 0; +} + +bool ux500_suspend_deepsleep_enabled(void) +{ + return deepsleep_enabled != 0; +} + +void ux500_suspend_dbg_sleep_status(bool is_deepsleep) +{ + u32 prcmu_status; + + prcmu_status = readl(prcmu_status_reg) & 0xff; + + if (is_deepsleep) { + pr_info("Returning from ApDeepSleep. PRCMU ret: 0x%x - %s\n", + prcmu_status, + prcmu_status == DEEP_SLEEP_OK ? "Success" : "Fail!"); + if (prcmu_status == DEEP_SLEEP_OK) + deepsleeps_done++; + else + deepsleeps_failed++; + } else { + pr_info("Returning from ApSleep. PRCMU ret: 0x%x - %s\n", + prcmu_status, + prcmu_status == SLEEP_OK ? "Success" : "Fail!"); + if (prcmu_status == SLEEP_OK) + sleeps_done++; + else + sleeps_failed++; + } +} + +int ux500_suspend_dbg_begin(suspend_state_t state) +{ + suspend_count++; + return 0; +} + +void ux500_suspend_dbg_init(void) +{ + struct dentry *suspend_dir = NULL; + struct dentry *sleep_file = NULL; + struct dentry *deepsleep_file = NULL; + struct dentry *enable_file = NULL; + struct dentry *suspend_count_file = NULL; + struct dentry *sleeps_done_file = NULL; + struct dentry *deepsleeps_done_file = NULL; + struct dentry *sleeps_failed_file = NULL; + struct dentry *deepsleeps_failed_file = NULL; + + + if (cpu_is_u8500v20_or_later()) + prcmu_status_reg = (void *)IO_ADDRESS(PRCMU_STATUS_REGISTER_V2); + else + prcmu_status_reg = (void *)IO_ADDRESS(PRCMU_STATUS_REGISTER_V1); + + suspend_dir = debugfs_create_dir("suspend", NULL); + if (IS_ERR_OR_NULL(suspend_dir)) + return; + + sleep_file = debugfs_create_bool("sleep", S_IWUGO | S_IRUGO, + suspend_dir, + &sleep_enabled); + if (IS_ERR_OR_NULL(sleep_file)) + goto error; + + deepsleep_file = debugfs_create_bool("deepsleep", S_IWUGO | S_IRUGO, + suspend_dir, + &deepsleep_enabled); + if (IS_ERR_OR_NULL(deepsleep_file)) + goto error; + + enable_file = debugfs_create_bool("enable", S_IWUGO | S_IRUGO, + suspend_dir, + &suspend_enabled); + if (IS_ERR_OR_NULL(enable_file)) + goto error; + + suspend_count_file = debugfs_create_u32("count", S_IRUGO, + suspend_dir, + &suspend_count); + if (IS_ERR_OR_NULL(suspend_count_file)) + goto error; + + sleeps_done_file = debugfs_create_u32("sleep_count", S_IRUGO, + suspend_dir, + &sleeps_done); + if (IS_ERR_OR_NULL(sleeps_done_file)) + goto error; + + deepsleeps_done_file = debugfs_create_u32("deepsleep_count", S_IRUGO, + suspend_dir, + &deepsleeps_done); + if (IS_ERR_OR_NULL(deepsleeps_done_file)) + goto error; + + + sleeps_failed_file = debugfs_create_u32("sleep_failed", S_IRUGO, + suspend_dir, + &sleeps_failed); + if (IS_ERR_OR_NULL(sleeps_failed_file)) + goto error; + + deepsleeps_failed_file = debugfs_create_u32("deepsleep_failed", S_IRUGO, + suspend_dir, + &deepsleeps_failed); + if (IS_ERR_OR_NULL(deepsleeps_failed_file)) + goto error; + + return; +error: + if (!IS_ERR_OR_NULL(deepsleeps_failed_file)) + debugfs_remove(deepsleeps_failed_file); + if (!IS_ERR_OR_NULL(sleeps_failed_file)) + debugfs_remove(sleeps_failed_file); + if (!IS_ERR_OR_NULL(deepsleeps_done_file)) + debugfs_remove(deepsleeps_done_file); + if (!IS_ERR_OR_NULL(sleeps_done_file)) + debugfs_remove(sleeps_done_file); + if (!IS_ERR_OR_NULL(suspend_count_file)) + debugfs_remove(suspend_count_file); + if (!IS_ERR_OR_NULL(enable_file)) + debugfs_remove(enable_file); + if (!IS_ERR_OR_NULL(deepsleep_file)) + debugfs_remove(deepsleep_file); + if (!IS_ERR_OR_NULL(sleep_file)) + debugfs_remove(sleep_file); + + debugfs_remove(suspend_dir); +} diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.h b/arch/arm/mach-ux500/pm/suspend_dbg.h new file mode 100644 index 00000000000..46cbe6e7014 --- /dev/null +++ b/arch/arm/mach-ux500/pm/suspend_dbg.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + */ + +#ifndef UX500_SUSPEND_DBG_H +#define UX500_SUSPEND_DBG_H + +#include <linux/kernel.h> +#include <linux/suspend.h> + +#ifdef CONFIG_UX500_SUSPEND_DBG_WAKE_ON_UART +void ux500_suspend_dbg_add_wake_on_uart(void); +void ux500_suspend_dbg_remove_wake_on_uart(void); +#else +static inline void ux500_suspend_dbg_add_wake_on_uart(void) { } +static inline void ux500_suspend_dbg_remove_wake_on_uart(void) { } +#endif + +#ifdef CONFIG_UX500_SUSPEND_DBG +bool ux500_suspend_enabled(void); +bool ux500_suspend_sleep_enabled(void); +bool ux500_suspend_deepsleep_enabled(void); +void ux500_suspend_dbg_sleep_status(bool is_deepsleep); +void ux500_suspend_dbg_init(void); +int ux500_suspend_dbg_begin(suspend_state_t state); + +#else +static inline bool ux500_suspend_enabled(void) +{ + return true; +} +static inline bool ux500_suspend_sleep_enabled(void) +{ +#ifdef CONFIG_UX500_SUSPEND_STANDBY + return true; +#else + return false; +#endif +} +static inline bool ux500_suspend_deepsleep_enabled(void) +{ +#ifdef CONFIG_UX500_SUSPEND_MEM + return true; +#else + return false; +#endif +} +static inline void ux500_suspend_dbg_sleep_status(bool is_deepsleep) { } +static inline void ux500_suspend_dbg_init(void) { } + +#define ux500_suspend_dbg_begin NULL + +#endif + +#endif diff --git a/arch/arm/mach-ux500/pm/usecase_gov.c b/arch/arm/mach-ux500/pm/usecase_gov.c new file mode 100644 index 00000000000..eca26539e97 --- /dev/null +++ b/arch/arm/mach-ux500/pm/usecase_gov.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Alexandre Torgue <alexandre.torgue@stericsson.com> for ST-Ericsson + * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/io.h> +#include <linux/earlysuspend.h> +#include <linux/cpu.h> +#include <linux/sched.h> +#include <linux/tick.h> +#include <linux/workqueue.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> + +#define CPULOAD_MEAS_DELAY 3000 /* 3 secondes of delta */ + +/* debug */ +static unsigned long debug; + +#define hp_printk \ + if (debug) \ + printk \ + +/* cpu load monitor struct */ +#define LOAD_MONITOR 4 +struct hotplug_cpu_info { + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_io; + unsigned int load[LOAD_MONITOR]; + unsigned int io[LOAD_MONITOR]; + unsigned int idx; +}; + +static DEFINE_PER_CPU(struct hotplug_cpu_info, hotplug_info); + +/* Auto trigger criteria */ +/* loadavg threshold */ +static unsigned long lower_threshold = 175; +static unsigned long upper_threshold = 450; +/* load balancing */ +static unsigned long max_unbalance = 210; +/* trend load */ +static unsigned long trend_unbalance = 40; +static unsigned long min_trend = 5; +/* instant load */ +static unsigned long max_instant = 85; + +/* Use case management */ +#define MAX_USECASE 4 +#define NORMAL_UC 0 +#define AUTO_UC 1 + +static unsigned long current_usecase = AUTO_UC; +static unsigned long updated_usecase = -1; + +char *name_usecase[MAX_USECASE] = { + "normal", + "auto", + "Speech Call", + "Low power MP3", +}; + +struct usecase_config { + unsigned long max_freq; + unsigned long multiplier; + unsigned long online; +}; + +static struct usecase_config usecase_conf[MAX_USECASE] = { + { /* normal */ + 1000000, + 1024, + 1 + }, + { /* auto */ + 400000, + 0, + 0 + }, + { /* speech call */ + 400000, + 0, + 0 + }, + { /* low power mp3 */ + 400000, + 0, + 1 + }, +}; + +/* daemon */ +static unsigned long enable = 1; +static unsigned long trig = 2; + +static struct delayed_work work_cpu_hotplug; +static struct early_suspend cpuhotplug_early_suspend; + +/* calculate loadavg */ +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + +extern int cpufreq_update_freq(int cpu, unsigned int min, unsigned int max); +extern int cpuidle_set_multiplier(unsigned int value); + +static unsigned long determine_loadavg(void) +{ + unsigned long avg = 0; + unsigned long avnrun[3]; + + get_avenrun(avnrun, FIXED_1 / 200, 0); + avg += (LOAD_INT(avnrun[0]) * 100) + (LOAD_FRAC(avnrun[0]) % 100); + + return avg; +} + +static unsigned long determine_cpu_load(void) +{ + int i; + unsigned long total_load = 0; + + /* get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load, iowait; + unsigned int idle_time, iowait_time, wall_time; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + /* update both cur_idle_time and cur_wall_time */ + cur_idle_time = get_cpu_idle_time_us(i, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time_us(i, &cur_wall_time); + + /* how much wall time has passed since last iteration? */ + wall_time = (unsigned int) cputime64_sub(cur_wall_time, + info->prev_cpu_wall); + info->prev_cpu_wall = cur_wall_time; + + /* how much idle time has passed since last iteration? */ + idle_time = (unsigned int) cputime64_sub(cur_idle_time, + info->prev_cpu_idle); + info->prev_cpu_idle = cur_idle_time; + + /* how much io wait time has passed since last iteration? */ + iowait_time = (unsigned int) cputime64_sub(cur_iowait_time, + info->prev_cpu_io); + info->prev_cpu_io = cur_iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + /* load is the percentage of time not spent in idle */ + load = 100 * (wall_time - idle_time) / wall_time; + info->load[info->idx] = load; + hp_printk("cpu %d load %u ", i, load); + + /* iowait is the percentage of time not spent in io wait */ + iowait = 100 * (iowait_time) / wall_time; + info->io[info->idx++] = load; + hp_printk("iowait %u\n", iowait); + + if (info->idx >= LOAD_MONITOR) + info->idx = 0; + + total_load += load; + } + + return total_load; +} + +static unsigned long determine_cpu_load_trend(void) +{ + int i, j, k; + unsigned long total_load = 0; + + /* Get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load = 0; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) + load += info->load[j]; + + load /= LOAD_MONITOR; + + hp_printk("cpu %d load trend %u\n", i, load); + + total_load += load; + } + + return total_load; +} + +static unsigned long determine_cpu_balance_trend(void) +{ + int i, j, k; + unsigned long total_load = 0; + unsigned long min_load = (unsigned long) (-1); + + /* Get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load = 0; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) + load += info->load[j]; + + load /= LOAD_MONITOR; + + if (min_load > load) + min_load = load; + total_load += load; + } + + if (min_load > min_trend) + total_load = (100 * total_load) / min_load; + else + total_load = 50 << num_online_cpus(); + + return total_load; +} + +static void init_cpu_load_trend(void) +{ + int i; + + for_each_possible_cpu(i) { + struct hotplug_cpu_info *info; + int j; + + info = &per_cpu(hotplug_info, i); + + info->prev_cpu_idle = get_cpu_idle_time_us(i, + &(info->prev_cpu_wall)); + info->prev_cpu_io = get_cpu_iowait_time_us(i, + &(info->prev_cpu_wall)); + + for (j = 0; j < LOAD_MONITOR; j++) { + info->load[j] = 100; + info->io[j] = 100; + } + info->idx = 0; + } +} + +static void set_cpu_config(int mode) +{ + static int previous_mode = -1; + + if (mode != previous_mode) { + previous_mode = mode; + + if (!(usecase_conf[mode].online) && (num_online_cpus() > 1)) + cpu_down(1); + else if ((usecase_conf[mode].online) && (num_online_cpus() < 2)) + cpu_up(1); + + cpufreq_update_freq(0, 0, usecase_conf[mode].max_freq); + cpuidle_set_multiplier(usecase_conf[mode].multiplier); + } +} + +/* + * Start load measurment every 6 s in order detrmine if can unplug one CPU. + * In order to not corrupt measurment, the first load average is not done + * here call in early suspend. + */ +static void start_cpu_hotplug_check(struct early_suspend *h) +{ + trig = 2; + init_cpu_load_trend(); + schedule_delayed_work_on(0, &work_cpu_hotplug, + msecs_to_jiffies(CPULOAD_MEAS_DELAY)); +} + +/* Stop measurement, call LCD early resume */ +static void stop_cpu_hotplug_check(struct early_suspend *h) +{ + cancel_delayed_work_sync(&work_cpu_hotplug); + + set_cpu_config(NORMAL_UC); + + trig = 2; +} + +static void delayed_cpu_hotplug_work(struct work_struct *work) +{ + unsigned long avg, load, trend, balance, tmp_trig; + + /* determine loadavg */ + avg = determine_loadavg(); + hp_printk("loadavg = %lu lower th %lu upper th %lu\n", + avg, lower_threshold, upper_threshold); + + /* determine instant load */ + load = determine_cpu_load(); + hp_printk("cpu instant load = %lu max %lu\n", load, max_instant); + + /* determine load trend */ + trend = determine_cpu_load_trend(); + hp_printk("cpu load trend = %lu min %lu unbal %lu\n", + trend, min_trend, trend_unbalance); + + /* determine load balancing */ + balance = determine_cpu_balance_trend(); + hp_printk("load balancing trend = %lu min %lu\n", + balance, max_unbalance); + + tmp_trig = trig; + hp_printk("current trig = %lu\n", tmp_trig); + + /* detect "instant" load increase */ + if (load > max_instant) { + tmp_trig++; + } else if (current_usecase == 1) { /* auto mode */ + /* detect high loadavg use case */ + if (avg > upper_threshold) + tmp_trig++; + /* detect idle use case */ + else if (trend < min_trend) + tmp_trig--; + /* detect unbalanced low cpu load use case */ + else if ((balance > max_unbalance) && (trend < trend_unbalance)) + tmp_trig--; + /* detect low loadavg use case */ + else if (avg < lower_threshold) + tmp_trig--; + } else { + tmp_trig--; + } + + if (updated_usecase != -1) { + current_usecase = updated_usecase; + updated_usecase = -1; + if (!tmp_trig) + tmp_trig = 1; + } + + if ((enable) && (tmp_trig == 1)) { + hp_printk("enter use case config\n"); + set_cpu_config(current_usecase); + trig = 1; + } else if (enable && (tmp_trig == 2)) { + hp_printk("enter normal config\n"); + set_cpu_config(NORMAL_UC); + trig = 2; + } + + /* reprogramm scheduled work */ + schedule_delayed_work_on(0, &work_cpu_hotplug, + msecs_to_jiffies(CPULOAD_MEAS_DELAY)); + +} + +#define define_set(_name) \ +static ssize_t set_##_name(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + char buf[32]; \ + ssize_t buf_size; \ + long unsigned int i; \ + \ + /* Get userspace string and assure termination */ \ + buf_size = min(count, (sizeof(buf)-1)); \ + if (copy_from_user(buf, user_buf, buf_size)) \ + return -EFAULT; \ + buf[buf_size] = 0; \ + \ + if (strict_strtoul(buf, 0, &i) != 0) \ + return buf_size; \ + \ + _name = i; \ + hp_printk("New value : %lu\n", _name); \ + \ + return buf_size; \ +} + +define_set(upper_threshold); +define_set(lower_threshold); +define_set(max_unbalance); +define_set(trend_unbalance); +define_set(min_trend); +define_set(max_instant); +define_set(enable); +define_set(debug); + +#define define_print(_name) \ +static ssize_t print_##_name(struct seq_file *s, void *p) \ +{ \ + return seq_printf(s, "%lu\n", _name); \ +} + +define_print(upper_threshold); +define_print(lower_threshold); +define_print(max_unbalance); +define_print(trend_unbalance); +define_print(min_trend); +define_print(max_instant); +define_print(enable); +define_print(debug); + +#define define_open(_name) \ +static ssize_t open_##_name(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, print_##_name, inode->i_private); \ +} + +define_open(upper_threshold); +define_open(lower_threshold); +define_open(max_unbalance); +define_open(trend_unbalance); +define_open(min_trend); +define_open(max_instant); +define_open(enable); +define_open(debug); + +#define define_dbg_file(_name) \ +static const struct file_operations fops_##_name = { \ + .open = open_##_name, \ + .write = set_##_name, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .owner = THIS_MODULE, \ +}; \ +static struct dentry *file_##_name; + +define_dbg_file(upper_threshold); +define_dbg_file(lower_threshold); +define_dbg_file(max_unbalance); +define_dbg_file(trend_unbalance); +define_dbg_file(min_trend); +define_dbg_file(max_instant); +define_dbg_file(enable); +define_dbg_file(debug); + +struct dbg_file { + struct dentry **file; + const struct file_operations *fops; + const char *name; +}; + +#define define_dbg_entry(_name) \ +{ \ + .file = &file_##_name, \ + .fops = &fops_##_name, \ + .name = #_name \ +} + +static struct dbg_file debug_entry[] = { + define_dbg_entry(upper_threshold), + define_dbg_entry(lower_threshold), + define_dbg_entry(max_unbalance), + define_dbg_entry(trend_unbalance), + define_dbg_entry(min_trend), + define_dbg_entry(max_instant), + define_dbg_entry(enable), + define_dbg_entry(debug), + { + .file = NULL, + }, +}; + +static struct dentry *cpuhotplug_dir; + +static void remove_debugfs(void) +{ + struct dbg_file *entry; + + entry = &debug_entry[0]; + while (entry->file != NULL) { + if (!IS_ERR_OR_NULL(*(entry->file))) + debugfs_remove(*(entry->file)); + entry++; + } +} + +static void setup_debugfs(void) +{ + struct dbg_file *entry; + + cpuhotplug_dir = debugfs_create_dir("cpu_hotplug", NULL); + + if (IS_ERR_OR_NULL(cpuhotplug_dir)) + goto fail; + + entry = &debug_entry[0]; + while (entry->file != NULL) { + *(entry->file) = debugfs_create_file(entry->name, + S_IWUGO | S_IRUGO, cpuhotplug_dir, + NULL, (entry->fops)); + + if (IS_ERR_OR_NULL(*(entry->file))) + break; + + entry++; + } + + return; +fail: + remove_debugfs(); +} + +static ssize_t show_mode(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%lu : %s\n", + current_usecase, name_usecase[current_usecase]); +} + +static ssize_t store_mode(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input < MAX_USECASE) + updated_usecase = input; + + return count; +} + +static SYSDEV_CLASS_ATTR(mode, 0644, show_mode, store_mode); + +static struct attribute *dbs_attributes[] = { + &attr_mode.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "usecase-gov", +}; + +/* initialize devices */ +int __init init_cpuhotplug_devices(void) +{ + int err; + + pr_info("Use-case governor initialized\n"); + + /* add early_suspend callback */ + cpuhotplug_early_suspend.level = 200; + cpuhotplug_early_suspend.suspend = start_cpu_hotplug_check; + cpuhotplug_early_suspend.resume = stop_cpu_hotplug_check; + register_early_suspend(&cpuhotplug_early_suspend); + + /* register delayed queuework */ + INIT_DELAYED_WORK_DEFERRABLE(&work_cpu_hotplug, + delayed_cpu_hotplug_work); + + init_cpu_load_trend(); + + setup_debugfs(); + + err = sysfs_create_group(&(cpu_sysdev_class.kset.kobj), + &dbs_attr_group); + if (err) { + pr_err("usecase-gov: sysfs_create_group" + " failed with error = %d\n", err); + goto error; + } + + + return 0; + +error: + remove_debugfs(); + unregister_early_suspend(&cpuhotplug_early_suspend); + return err; +} + +module_init(init_cpuhotplug_devices); diff --git a/arch/arm/mach-ux500/prcmu-db5500.c b/arch/arm/mach-ux500/prcmu-db5500.c new file mode 100644 index 00000000000..e5d90ae367f --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-db5500.c @@ -0,0 +1,546 @@ +/* + * 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 <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/prcmu-regs.h> +#include <mach/prcmu-db5500.h> +#include <mach/prcmu-fw-api.h> +#include <mach/db5500-regs.h> + +#include "prcmu-regs-db5500.h" +#include "prcmu-db5500.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 0x00020121 +#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002 +#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000201 +#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; + +struct clk_mgt { + unsigned int offset; + u32 pllsw; +}; + +static DEFINE_SPINLOCK(clk_mgt_lock); + +#define CLK_MGT_ENTRY(_name)[DB5500_PRCMU_##_name] = { \ + (DB5500_PRCM_##_name##_MGT), 0 \ +} +static struct clk_mgt clk_mgt[DB5500_PRCMU_NUM_REG_CLOCKS] = { + CLK_MGT_ENTRY(SGACLK), + CLK_MGT_ENTRY(UARTCLK), + CLK_MGT_ENTRY(MSP02CLK), + CLK_MGT_ENTRY(I2CCLK), + CLK_MGT_ENTRY(SDMMCCLK), + CLK_MGT_ENTRY(PER1CLK), + CLK_MGT_ENTRY(PER2CLK), + CLK_MGT_ENTRY(PER3CLK), + CLK_MGT_ENTRY(PER5CLK), + CLK_MGT_ENTRY(PER6CLK), + CLK_MGT_ENTRY(PWMCLK), + CLK_MGT_ENTRY(IRDACLK), + CLK_MGT_ENTRY(IRRCCLK), + CLK_MGT_ENTRY(HDMICLK), + CLK_MGT_ENTRY(APEATCLK), + CLK_MGT_ENTRY(APETRACECLK), + CLK_MGT_ENTRY(MCDECLK), + CLK_MGT_ENTRY(DSIALTCLK), + CLK_MGT_ENTRY(DMACLK), + CLK_MGT_ENTRY(B2R2CLK), + CLK_MGT_ENTRY(TVCLK), + CLK_MGT_ENTRY(RNGCLK), +}; + +static int request_timclk(bool enable) +{ + u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); + + if (!enable) + val |= PRCM_TCR_STOP_TIMERS; + writel(val, (_PRCMU_BASE + PRCM_TCR)); + + return 0; +} + +static int request_reg_clock(u8 clock, bool enable) +{ + u32 val; + unsigned long flags; + + WARN_ON(!clk_mgt[clock].offset); + + spin_lock_irqsave(&clk_mgt_lock, flags); + + /* Grab the HW semaphore. */ + while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) + cpu_relax(); + + val = readl(_PRCMU_BASE + clk_mgt[clock].offset); + if (enable) { + val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw); + } else { + clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK); + val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK); + } + writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); + + /* Release the HW semaphore. */ + writel(0, (_PRCMU_BASE + PRCM_SEM)); + + spin_unlock_irqrestore(&clk_mgt_lock, flags); + + return 0; +} + +/** + * db5500_prcmu_request_clock() - Request for a clock to be enabled or disabled. + * @clock: The clock for which the request is made. + * @enable: Whether the clock should be enabled (true) or disabled (false). + * + * This function should only be used by the clock implementation. + * Do not use it from any other place! + */ +int db5500_prcmu_request_clock(u8 clock, bool enable) +{ + if (clock < DB5500_PRCMU_NUM_REG_CLOCKS) + return request_reg_clock(clock, enable); + else if (clock == DB5500_PRCMU_TIMCLK) + return request_timclk(enable); + else if (clock == DB5500_PRCMU_SYSCLK) + return -EINVAL; + else + return -EINVAL; +} + +/** + * 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 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 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 prcmu_set_display_clocks(void) +{ + writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT); + 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); diff --git a/arch/arm/mach-ux500/prcmu-db5500.h b/arch/arm/mach-ux500/prcmu-db5500.h new file mode 100644 index 00000000000..713bd0d858d --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-db5500.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License, version 2 + */ + +#ifndef __MACH_PRCMU_DB4500_H +#define __MACH_PRCMU_DB4500_H + +/* + * Clock identifiers. + */ +enum db5500_prcmu_clock { + DB5500_PRCMU_SGACLK, + DB5500_PRCMU_UARTCLK, + DB5500_PRCMU_MSP02CLK, + DB5500_PRCMU_I2CCLK, + DB5500_PRCMU_SDMMCCLK, + DB5500_PRCMU_PER1CLK, + DB5500_PRCMU_PER2CLK, + DB5500_PRCMU_PER3CLK, + DB5500_PRCMU_PER5CLK, + DB5500_PRCMU_PER6CLK, + DB5500_PRCMU_PWMCLK, + DB5500_PRCMU_IRDACLK, + DB5500_PRCMU_IRRCCLK, + DB5500_PRCMU_HDMICLK, + DB5500_PRCMU_APEATCLK, + DB5500_PRCMU_APETRACECLK, + DB5500_PRCMU_MCDECLK, + DB5500_PRCMU_DSIALTCLK, + DB5500_PRCMU_DMACLK, + DB5500_PRCMU_B2R2CLK, + DB5500_PRCMU_TVCLK, + DB5500_PRCMU_RNGCLK, + DB5500_PRCMU_NUM_REG_CLOCKS, + DB5500_PRCMU_SYSCLK = DB5500_PRCMU_NUM_REG_CLOCKS, + DB5500_PRCMU_TIMCLK, +}; + +extern int db5500_prcmu_request_clock(u8 clock, bool enable); + +#endif diff --git a/arch/arm/mach-ux500/prcmu-db8500.c b/arch/arm/mach-ux500/prcmu-db8500.c new file mode 100644 index 00000000000..edb7003aaa0 --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-db8500.c @@ -0,0 +1,2058 @@ +/* + * 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/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/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> + +/* + * NOTE! Temporary until all users of set_hwacc() are using the regulator + * framework API + */ +#include <linux/regulator/consumer.h> + +#include <mach/hardware.h> +#include <mach/irqs.h> +#include "prcmu-regs-db8500.h" +#include "prcmu-debug.h" +#include <mach/prcmu-fw-api.h> +#include <mach/prcmu-fw-defs_v1.h> +#include <mach/db8500-regs.h> + +/* Offset for the firmware version within the TCPM */ +#define PRCMU_FW_VERSION_OFFSET 0xA4 + +/* PRCMU project numbers, defined by PRCMU FW */ +#define PRCMU_PROJECT_ID_8500V1_0 1 +#define PRCMU_PROJECT_ID_8500V2_0 2 +#define PRCMU_PROJECT_ID_8400V2_0 3 + +/* Index of different voltages to be used when accessing AVSData */ +#define PRCM_AVS_BASE 0x2FC +#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0) +#define PRCM_AVS_VBB_MAX_OPP (PRCM_AVS_BASE + 0x1) +#define PRCM_AVS_VBB_100_OPP (PRCM_AVS_BASE + 0x2) +#define PRCM_AVS_VBB_50_OPP (PRCM_AVS_BASE + 0x3) +#define PRCM_AVS_VARM_MAX_OPP (PRCM_AVS_BASE + 0x4) +#define PRCM_AVS_VARM_100_OPP (PRCM_AVS_BASE + 0x5) +#define PRCM_AVS_VARM_50_OPP (PRCM_AVS_BASE + 0x6) +#define PRCM_AVS_VARM_RET (PRCM_AVS_BASE + 0x7) +#define PRCM_AVS_VAPE_100_OPP (PRCM_AVS_BASE + 0x8) +#define PRCM_AVS_VAPE_50_OPP (PRCM_AVS_BASE + 0x9) +#define PRCM_AVS_VMOD_100_OPP (PRCM_AVS_BASE + 0xA) +#define PRCM_AVS_VMOD_50_OPP (PRCM_AVS_BASE + 0xB) +#define PRCM_AVS_VSAFE (PRCM_AVS_BASE + 0xC) + +#define PRCM_AVS_VOLTAGE 0 +#define PRCM_AVS_VOLTAGE_MASK 0x3f +#define PRCM_AVS_ISSLOWSTARTUP 6 +#define PRCM_AVS_ISSLOWSTARTUP_MASK (1 << PRCM_AVS_ISSLOWSTARTUP) +#define PRCM_AVS_ISMODEENABLE 7 +#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE) + +#define PRCM_BOOT_STATUS 0xFFF +#define PRCM_ROMCODE_A2P 0xFFE +#define PRCM_ROMCODE_P2A 0xFFD +#define PRCM_XP70_CUR_PWR_STATE 0xFFC /* 4 BYTES */ + +#define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */ + +#define _PRCM_MBOX_HEADER 0xFE8 /* 16 bytes */ +#define PRCM_MBOX_HEADER_REQ_MB0 (_PRCM_MBOX_HEADER + 0x0) +#define PRCM_MBOX_HEADER_REQ_MB1 (_PRCM_MBOX_HEADER + 0x1) +#define PRCM_MBOX_HEADER_REQ_MB2 (_PRCM_MBOX_HEADER + 0x2) +#define PRCM_MBOX_HEADER_REQ_MB3 (_PRCM_MBOX_HEADER + 0x3) +#define PRCM_MBOX_HEADER_REQ_MB4 (_PRCM_MBOX_HEADER + 0x4) +#define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5) +#define PRCM_MBOX_HEADER_ACK_MB0 (_PRCM_MBOX_HEADER + 0x8) + +/* Req Mailboxes */ +#define PRCM_REQ_MB0 0xFDC /* 12 bytes */ +#define PRCM_REQ_MB1 0xFD0 /* 12 bytes */ +#define PRCM_REQ_MB2 0xFC0 /* 16 bytes */ +#define PRCM_REQ_MB3 0xE4C /* 372 bytes */ +#define PRCM_REQ_MB4 0xE48 /* 4 bytes */ +#define PRCM_REQ_MB5 0xE44 /* 4 bytes */ + +/* Ack Mailboxes */ +#define PRCM_ACK_MB0 0xE08 /* 52 bytes */ +#define PRCM_ACK_MB1 0xE04 /* 4 bytes */ +#define PRCM_ACK_MB2 0xE00 /* 4 bytes */ +#define PRCM_ACK_MB3 0xDFC /* 4 bytes */ +#define PRCM_ACK_MB4 0xDF8 /* 4 bytes */ +#define PRCM_ACK_MB5 0xDF4 /* 4 bytes */ + +/* Mailbox 0 headers */ +#define MB0H_POWER_STATE_TRANS 0 +#define MB0H_CONFIG_WAKEUPS_EXE 1 +#define MB0H_READ_WAKEUP_ACK 3 +#define MB0H_CONFIG_WAKEUPS_SLEEP 4 + +#define MB0H_WAKEUP_EXE 2 +#define MB0H_WAKEUP_SLEEP 5 + +/* Mailbox 0 REQs */ +#define PRCM_REQ_MB0_AP_POWER_STATE (PRCM_REQ_MB0 + 0x0) +#define PRCM_REQ_MB0_AP_PLL_STATE (PRCM_REQ_MB0 + 0x1) +#define PRCM_REQ_MB0_ULP_CLOCK_STATE (PRCM_REQ_MB0 + 0x2) +#define PRCM_REQ_MB0_DO_NOT_WFI (PRCM_REQ_MB0 + 0x3) +#define PRCM_REQ_MB0_WAKEUP_8500 (PRCM_REQ_MB0 + 0x4) +#define PRCM_REQ_MB0_WAKEUP_4500 (PRCM_REQ_MB0 + 0x8) + +/* Mailbox 0 ACKs */ +#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0) +#define PRCM_ACK_MB0_READ_POINTER (PRCM_ACK_MB0 + 0x1) +#define PRCM_ACK_MB0_WAKEUP_0_8500 (PRCM_ACK_MB0 + 0x4) +#define PRCM_ACK_MB0_WAKEUP_0_4500 (PRCM_ACK_MB0 + 0x8) +#define PRCM_ACK_MB0_WAKEUP_1_8500 (PRCM_ACK_MB0 + 0x1C) +#define PRCM_ACK_MB0_WAKEUP_1_4500 (PRCM_ACK_MB0 + 0x20) +#define PRCM_ACK_MB0_EVENT_4500_NUMBERS 20 + +/* Mailbox 1 headers */ +#define MB1H_ARM_APE_OPP 0x0 +#define MB1H_RESET_MODEM 0x2 +#define MB1H_REQUEST_APE_OPP_100_VOLT 0x3 +#define MB1H_RELEASE_APE_OPP_100_VOLT 0x4 +#define MB1H_RELEASE_USB_WAKEUP 0x5 +#define MB1H_PLL_ON_OFF 0x6 + +/* Mailbox 1 Requests */ +#define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0) +#define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1) +#define PRCM_REQ_MB1_APE_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x4) +#define PRCM_REQ_MB1_ARM_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x8) +#define PRCM_REQ_MB1_PLL_ON_OFF (PRCM_REQ_MB1 + 0x4) +#define PLL_SOC1_OFF 0x4 +#define PLL_SOC1_ON 0x8 + +/* Mailbox 1 ACKs */ +#define PRCM_ACK_MB1_CURRENT_ARM_OPP (PRCM_ACK_MB1 + 0x0) +#define PRCM_ACK_MB1_CURRENT_APE_OPP (PRCM_ACK_MB1 + 0x1) +#define PRCM_ACK_MB1_APE_VOLTAGE_STATUS (PRCM_ACK_MB1 + 0x2) +#define PRCM_ACK_MB1_DVFS_STATUS (PRCM_ACK_MB1 + 0x3) + +/* Mailbox 2 headers */ +#define MB2H_DPS 0x0 +#define MB2H_AUTO_PWR 0x1 + +/* Mailbox 2 REQs */ +#define PRCM_REQ_MB2_SVA_MMDSP (PRCM_REQ_MB2 + 0x0) +#define PRCM_REQ_MB2_SVA_PIPE (PRCM_REQ_MB2 + 0x1) +#define PRCM_REQ_MB2_SIA_MMDSP (PRCM_REQ_MB2 + 0x2) +#define PRCM_REQ_MB2_SIA_PIPE (PRCM_REQ_MB2 + 0x3) +#define PRCM_REQ_MB2_SGA (PRCM_REQ_MB2 + 0x4) +#define PRCM_REQ_MB2_B2R2_MCDE (PRCM_REQ_MB2 + 0x5) +#define PRCM_REQ_MB2_ESRAM12 (PRCM_REQ_MB2 + 0x6) +#define PRCM_REQ_MB2_ESRAM34 (PRCM_REQ_MB2 + 0x7) +#define PRCM_REQ_MB2_AUTO_PM_SLEEP (PRCM_REQ_MB2 + 0x8) +#define PRCM_REQ_MB2_AUTO_PM_IDLE (PRCM_REQ_MB2 + 0xC) + +/* Mailbox 2 ACKs */ +#define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0) +#define HWACC_PWR_ST_OK 0xFE + +/* Mailbox 3 headers */ +#define MB3H_ANC 0x0 +#define MB3H_SIDETONE 0x1 +#define MB3H_SYSCLK 0xE + +/* Mailbox 3 Requests */ +#define PRCM_REQ_MB3_ANC_FIR_COEFF (PRCM_REQ_MB3 + 0x0) +#define PRCM_REQ_MB3_ANC_IIR_COEFF (PRCM_REQ_MB3 + 0x20) +#define PRCM_REQ_MB3_ANC_SHIFTER (PRCM_REQ_MB3 + 0x60) +#define PRCM_REQ_MB3_ANC_WARP (PRCM_REQ_MB3 + 0x64) +#define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68) +#define PRCM_REQ_MB3_SIDETONE_FIR_COEFF (PRCM_REQ_MB3 + 0x6C) +#define PRCM_REQ_MB3_SYSCLK_MGT (PRCM_REQ_MB3 + 0x16C) + +/* Mailbox 4 headers */ +#define MB4H_DDR_INIT 0x0 +#define MB4H_MEM_ST 0x1 +#define MB4H_HOTDOG 0x12 +#define MB4H_HOTMON 0x13 +#define MB4H_HOT_PERIOD 0x14 + +/* Mailbox 4 Requests */ +#define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE (PRCM_REQ_MB4 + 0x0) +#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE (PRCM_REQ_MB4 + 0x1) +#define PRCM_REQ_MB4_ESRAM0_ST (PRCM_REQ_MB4 + 0x3) +#define PRCM_REQ_MB4_HOTDOG_THRESHOLD (PRCM_REQ_MB4 + 0x0) +#define PRCM_REQ_MB4_HOTMON_LOW (PRCM_REQ_MB4 + 0x0) +#define PRCM_REQ_MB4_HOTMON_HIGH (PRCM_REQ_MB4 + 0x1) +#define PRCM_REQ_MB4_HOTMON_CONFIG (PRCM_REQ_MB4 + 0x2) +#define PRCM_REQ_MB4_HOT_PERIOD (PRCM_REQ_MB4 + 0x0) +#define HOTMON_CONFIG_LOW BIT(0) +#define HOTMON_CONFIG_HIGH BIT(1) + +/* Mailbox 5 Requests */ +#define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0) +#define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1) +#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2) +#define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3) +#define PRCMU_I2C_WRITE(slave) \ + (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) +#define PRCMU_I2C_READ(slave) \ + (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0)) +#define PRCMU_I2C_STOP_EN BIT(3) + +/* Mailbox 5 ACKs */ +#define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1) +#define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3) +#define I2C_WR_OK 0x1 +#define I2C_RD_OK 0x2 + +#define NUM_MB 8 +#define MBOX_BIT BIT +#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) + +/* + * Wakeups/IRQs + */ + +#define WAKEUP_BIT_RTC BIT(0) +#define WAKEUP_BIT_RTT0 BIT(1) +#define WAKEUP_BIT_RTT1 BIT(2) +#define WAKEUP_BIT_HSI0 BIT(3) +#define WAKEUP_BIT_HSI1 BIT(4) +#define WAKEUP_BIT_CA_WAKE BIT(5) +#define WAKEUP_BIT_USB BIT(6) +#define WAKEUP_BIT_ABB BIT(7) +#define WAKEUP_BIT_ABB_FIFO BIT(8) +#define WAKEUP_BIT_SYSCLK_OK BIT(9) +#define WAKEUP_BIT_CA_SLEEP BIT(10) +#define WAKEUP_BIT_AC_WAKE_ACK BIT(11) +#define WAKEUP_BIT_SIDE_TONE_OK BIT(12) +#define WAKEUP_BIT_ANC_OK BIT(13) +#define WAKEUP_BIT_SW_ERROR BIT(14) +#define WAKEUP_BIT_AC_SLEEP_ACK BIT(15) +#define WAKEUP_BIT_ARM BIT(17) +#define WAKEUP_BIT_HOTMON_LOW BIT(18) +#define WAKEUP_BIT_HOTMON_HIGH BIT(19) +#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20) +#define WAKEUP_BIT_GPIO0 BIT(23) +#define WAKEUP_BIT_GPIO1 BIT(24) +#define WAKEUP_BIT_GPIO2 BIT(25) +#define WAKEUP_BIT_GPIO3 BIT(26) +#define WAKEUP_BIT_GPIO4 BIT(27) +#define WAKEUP_BIT_GPIO5 BIT(28) +#define WAKEUP_BIT_GPIO6 BIT(29) +#define WAKEUP_BIT_GPIO7 BIT(30) +#define WAKEUP_BIT_GPIO8 BIT(31) + +/* + * This vector maps irq numbers to the bits in the bit field used in + * communication with the PRCMU firmware. + * + * The reason for having this is to keep the irq numbers contiguous even though + * the bits in the bit field are not. (The bits also have a tendency to move + * around, to further complicate matters.) + */ +#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE) +#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name) +static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = { + IRQ_ENTRY(RTC), + IRQ_ENTRY(RTT0), + IRQ_ENTRY(RTT1), + IRQ_ENTRY(HSI0), + IRQ_ENTRY(HSI1), + IRQ_ENTRY(CA_WAKE), + IRQ_ENTRY(USB), + IRQ_ENTRY(ABB), + IRQ_ENTRY(ABB_FIFO), + IRQ_ENTRY(CA_SLEEP), + IRQ_ENTRY(ARM), + IRQ_ENTRY(HOTMON_LOW), + IRQ_ENTRY(HOTMON_HIGH), + IRQ_ENTRY(MODEM_SW_RESET_REQ), + IRQ_ENTRY(GPIO0), + IRQ_ENTRY(GPIO1), + IRQ_ENTRY(GPIO2), + IRQ_ENTRY(GPIO3), + IRQ_ENTRY(GPIO4), + IRQ_ENTRY(GPIO5), + IRQ_ENTRY(GPIO6), + IRQ_ENTRY(GPIO7), + IRQ_ENTRY(GPIO8) +}; + +#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1) +#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name) +static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = { + WAKEUP_ENTRY(RTC), + WAKEUP_ENTRY(RTT0), + WAKEUP_ENTRY(RTT1), + WAKEUP_ENTRY(HSI0), + WAKEUP_ENTRY(HSI1), + WAKEUP_ENTRY(USB), + WAKEUP_ENTRY(ABB), + WAKEUP_ENTRY(ABB_FIFO), + WAKEUP_ENTRY(ARM) +}; + +/* + * mb0_transfer - state needed for mailbox 0 communication. + * @lock: The transaction lock. + * @dbb_events_lock: A lock used to handle concurrent access to (parts of) + * the request data. + * @mask_work: Work structure used for (un)masking wakeup interrupts. + * @req: Request data that need to persist between requests. + */ +static struct { + spinlock_t lock; + spinlock_t dbb_irqs_lock; + struct work_struct mask_work; + struct mutex ac_wake_lock; + struct completion ac_wake_work; + struct { + u32 dbb_irqs; + u32 dbb_wakeups; + u32 abb_events; + } req; +} mb0_transfer; + +/* + * mb1_transfer - state needed for mailbox 1 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 arm_opp; + u8 ape_opp; + u8 ape_voltage_status; + } ack; +} mb1_transfer; + +/* + * mb2_transfer - state needed for mailbox 2 communication. + * @lock: The transaction lock. + * @work: The transaction completion structure. + * @auto_pm_lock: The autonomous power management configuration lock. + * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled. + * @req: Request data that need to persist between requests. + * @ack: Reply ("acknowledge") data. + */ +static struct { + struct mutex lock; + struct completion work; + spinlock_t auto_pm_lock; + bool auto_pm_enabled; + struct { + u8 status; + } ack; +} mb2_transfer; + +/* + * mb3_transfer - state needed for mailbox 3 communication. + * @lock: The request lock. + * @sysclk_lock: A lock used to handle concurrent sysclk requests. + * @sysclk_work: Work structure used for sysclk requests. + */ +static struct { + spinlock_t lock; + struct mutex sysclk_lock; + struct completion sysclk_work; +} mb3_transfer; + +/* + * mb4_transfer - state needed for mailbox 4 communication. + * @lock: The transaction lock. + * @work: The transaction completion structure. + */ +static struct { + struct mutex lock; + struct completion work; +} mb4_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 status; + u8 value; + } ack; +} mb5_transfer; + +static atomic_t ac_wake_req_state = ATOMIC_INIT(0); + +/* Spinlocks */ +static DEFINE_SPINLOCK(clkout_lock); +static DEFINE_SPINLOCK(gpiocr_lock); + +/* Global var to runtime determine TCDM base for v2 or v1 */ +static __iomem void *tcdm_base; + +struct clk_mgt { + unsigned int offset; + u32 pllsw; +}; + +static DEFINE_SPINLOCK(clk_mgt_lock); + +#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 } +struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { + CLK_MGT_ENTRY(SGACLK), + CLK_MGT_ENTRY(UARTCLK), + CLK_MGT_ENTRY(MSP02CLK), + CLK_MGT_ENTRY(MSP1CLK), + CLK_MGT_ENTRY(I2CCLK), + CLK_MGT_ENTRY(SDMMCCLK), + CLK_MGT_ENTRY(SLIMCLK), + CLK_MGT_ENTRY(PER1CLK), + CLK_MGT_ENTRY(PER2CLK), + CLK_MGT_ENTRY(PER3CLK), + CLK_MGT_ENTRY(PER5CLK), + CLK_MGT_ENTRY(PER6CLK), + CLK_MGT_ENTRY(PER7CLK), + CLK_MGT_ENTRY(LCDCLK), + CLK_MGT_ENTRY(BMLCLK), + CLK_MGT_ENTRY(HSITXCLK), + CLK_MGT_ENTRY(HSIRXCLK), + CLK_MGT_ENTRY(HDMICLK), + CLK_MGT_ENTRY(APEATCLK), + CLK_MGT_ENTRY(APETRACECLK), + CLK_MGT_ENTRY(MCDECLK), + CLK_MGT_ENTRY(IPI2CCLK), + CLK_MGT_ENTRY(DSIALTCLK), + CLK_MGT_ENTRY(DMACLK), + CLK_MGT_ENTRY(B2R2CLK), + CLK_MGT_ENTRY(TVCLK), + CLK_MGT_ENTRY(SSPCLK), + CLK_MGT_ENTRY(RNGCLK), + CLK_MGT_ENTRY(UICCCLK), +}; + +/* + * NOTE! Temporary until all users of set_hwacc() are using the regulator + * framework API + */ +static struct regulator *hwacc_regulator[NUM_HW_ACC]; +static struct regulator *hwacc_ret_regulator[NUM_HW_ACC]; + +static bool hwacc_enabled[NUM_HW_ACC]; +static bool hwacc_ret_enabled[NUM_HW_ACC]; + +static const char *hwacc_regulator_name[NUM_HW_ACC] = { + [HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp", + [HW_ACC_SVAPIPE] = "hwacc-sva-pipe", + [HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp", + [HW_ACC_SIAPIPE] = "hwacc-sia-pipe", + [HW_ACC_SGA] = "hwacc-sga", + [HW_ACC_B2R2] = "hwacc-b2r2", + [HW_ACC_MCDE] = "hwacc-mcde", + [HW_ACC_ESRAM1] = "hwacc-esram1", + [HW_ACC_ESRAM2] = "hwacc-esram2", + [HW_ACC_ESRAM3] = "hwacc-esram3", + [HW_ACC_ESRAM4] = "hwacc-esram4", +}; + +static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = { + [HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp-ret", + [HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp-ret", + [HW_ACC_ESRAM1] = "hwacc-esram1-ret", + [HW_ACC_ESRAM2] = "hwacc-esram2-ret", + [HW_ACC_ESRAM3] = "hwacc-esram3-ret", + [HW_ACC_ESRAM4] = "hwacc-esram4-ret", +}; + +/* +* Used by MCDE to setup all necessary PRCMU registers +*/ +#define PRCMU_RESET_DSIPLL 0x00004000 +#define PRCMU_UNCLAMP_DSIPLL 0x00400800 + +#define PRCMU_CLK_PLL_DIV_SHIFT 0 +#define PRCMU_CLK_PLL_SW_SHIFT 5 +#define PRCMU_CLK_38 (1 << 9) +#define PRCMU_CLK_38_SRC (1 << 10) +#define PRCMU_CLK_38_DIV (1 << 11) + +/* PLLDIV=12, PLLSW=4 (PLLDDR) */ +#define PRCMU_DSI_CLOCK_SETTING 0x0000008C + +/* PLLDIV=8, PLLSW=4 (PLLDDR) */ +#define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088 + +/* DPI 50000000 Hz */ +#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \ + (16 << PRCMU_CLK_PLL_DIV_SHIFT)) +#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00 + +/* D=101, N=1, R=4, SELDIV2=0 */ +#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165 + +/* D=70, N=1, R=3, SELDIV2=0 */ +#define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146 + +#define PRCMU_ENABLE_PLLDSI 0x00000001 +#define PRCMU_DISABLE_PLLDSI 0x00000000 +#define PRCMU_RELEASE_RESET_DSS 0x0000400C +#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202 +/* ESC clk, div0=1, div1=1, div2=3 */ +#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101 +#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101 +#define PRCMU_DSI_RESET_SW 0x00000007 + +#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 + +static struct { + u8 project_number; + u8 api_version; + u8 func_version; + u8 errata; +} prcmu_version; + + +int prcmu_enable_dsipll(void) +{ + int i; + unsigned int plldsifreq; + + /* Clear DSIPLL_RESETN */ + writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR)); + /* Unclamp DSIPLL in/out */ + writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR)); + + if (prcmu_is_u8400()) + plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400; + else + plldsifreq = PRCMU_PLLDSI_FREQ_SETTING; + /* Set DSI PLL FREQ */ + writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ)); + writel(PRCMU_DSI_PLLOUT_SEL_SETTING, + (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL)); + /* Enable Escape clocks */ + writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, + (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); + + /* Start DSI PLL */ + writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); + /* Reset DSI PLL */ + writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET)); + for (i = 0; i < 10; i++) { + if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) & + PRCMU_PLLDSI_LOCKP_LOCKED) + == PRCMU_PLLDSI_LOCKP_LOCKED) + break; + udelay(100); + } + /* Set DSIPLL_RESETN */ + writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET)); + return 0; +} + +int prcmu_disable_dsipll(void) +{ + /* Disable dsi pll */ + writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); + /* Disable escapeclock */ + writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, + (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); + return 0; +} + +int prcmu_set_display_clocks(void) +{ + unsigned long flags; + unsigned int dsiclk; + + if (prcmu_is_u8400()) + dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400; + else + dsiclk = PRCMU_DSI_CLOCK_SETTING; + + spin_lock_irqsave(&clk_mgt_lock, flags); + + /* Grab the HW semaphore. */ + while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) + cpu_relax(); + + writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT)); + writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT)); + writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT)); + + /* Release the HW semaphore. */ + writel(0, (_PRCMU_BASE + PRCM_SEM)); + + spin_unlock_irqrestore(&clk_mgt_lock, flags); + + return 0; +} + +/** + * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1. + */ +void prcmu_enable_spi2(void) +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&gpiocr_lock, flags); + reg = readl(_PRCMU_BASE + PRCM_GPIOCR); + writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); + spin_unlock_irqrestore(&gpiocr_lock, flags); +} + +/** + * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1. + */ +void prcmu_disable_spi2(void) +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&gpiocr_lock, flags); + reg = readl(_PRCMU_BASE + PRCM_GPIOCR); + writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); + spin_unlock_irqrestore(&gpiocr_lock, flags); +} + +bool prcmu_has_arm_maxopp(void) +{ + return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) & + PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK; +} + +bool prcmu_is_u8400(void) +{ + return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0; +} + +/** + * prcmu_get_boot_status - PRCMU boot status checking + * Returns: the current PRCMU boot status + */ +int prcmu_get_boot_status(void) +{ + return readb(tcdm_base + PRCM_BOOT_STATUS); +} + +/** + * prcmu_set_rc_a2p - This function is used to run few power state sequences + * @val: Value to be set, i.e. transition requested + * Returns: 0 on success, -EINVAL on invalid argument + * + * This function is used to run the following power state sequences - + * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep + */ +int prcmu_set_rc_a2p(enum romcode_write val) +{ + if (val < RDY_2_DS || val > RDY_2_XP70_RST) + return -EINVAL; + writeb(val, (tcdm_base + PRCM_ROMCODE_A2P)); + return 0; +} + +/** + * prcmu_get_rc_p2a - This function is used to get power state sequences + * Returns: the power transition that has last happened + * + * This function can return the following transitions- + * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep + */ +enum romcode_read prcmu_get_rc_p2a(void) +{ + return readb(tcdm_base + PRCM_ROMCODE_P2A); +} + +/** + * prcmu_get_current_mode - Return the current XP70 power mode + * Returns: Returns the current AP(ARM) power mode: init, + * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset + */ +enum ap_pwrst prcmu_get_xp70_current_state(void) +{ + return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE); +} + +/** + * prcmu_config_clkout - Configure one of the programmable clock outputs. + * @clkout: The CLKOUT number (0 or 1). + * @source: The clock to be used (one of the PRCMU_CLKSRC_*). + * @div: The divider to be applied. + * + * Configures one of the programmable clock outputs (CLKOUTs). + * @div should be in the range [1,63] to request a configuration, or 0 to + * inform that the configuration is no longer requested. + */ +int prcmu_config_clkout(u8 clkout, u8 source, u8 div) +{ + static int requests[2]; + int r = 0; + unsigned long flags; + u32 val; + u32 bits; + u32 mask; + u32 div_mask; + + BUG_ON(clkout > 1); + BUG_ON(div > 63); + BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009)); + + if (!div && !requests[clkout]) + return -EINVAL; + + switch (clkout) { + case 0: + div_mask = PRCM_CLKOCR_CLKODIV0_MASK; + mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK); + bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) | + (div << PRCM_CLKOCR_CLKODIV0_SHIFT)); + break; + case 1: + div_mask = PRCM_CLKOCR_CLKODIV1_MASK; + mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK | + PRCM_CLKOCR_CLK1TYPE); + bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) | + (div << PRCM_CLKOCR_CLKODIV1_SHIFT)); + break; + } + bits &= mask; + + spin_lock_irqsave(&clkout_lock, flags); + + val = readl(_PRCMU_BASE + PRCM_CLKOCR); + if (val & div_mask) { + if (div) { + if ((val & mask) != bits) { + r = -EBUSY; + goto unlock_and_return; + } + } else { + if ((val & mask & ~div_mask) != bits) { + r = -EINVAL; + goto unlock_and_return; + } + } + } + writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR)); + requests[clkout] += (div ? 1 : -1); + +unlock_and_return: + spin_unlock_irqrestore(&clkout_lock, flags); + + return r; +} + +int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) +{ + unsigned long flags; + + BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state)); + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) + cpu_relax(); + + writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); + writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE)); + writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE)); + writeb((keep_ulp_clk ? 1 : 0), + (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE)); + writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI)); + writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); + + return 0; +} + +/* This function should only be called while mb0_transfer.lock is held. */ +static void config_wakeups(void) +{ + const u8 header[2] = { + MB0H_CONFIG_WAKEUPS_EXE, + MB0H_CONFIG_WAKEUPS_SLEEP + }; + static u32 last_dbb_events; + static u32 last_abb_events; + u32 dbb_events; + u32 abb_events; + unsigned int i; + + dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups; + dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK); + + abb_events = mb0_transfer.req.abb_events; + + if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events)) + return; + + for (i = 0; i < 2; i++) { + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) + cpu_relax(); + writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500)); + writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500)); + writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); + writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + } + last_dbb_events = dbb_events; + last_abb_events = abb_events; +} + +void prcmu_enable_wakeups(u32 wakeups) +{ + unsigned long flags; + u32 bits; + int i; + + BUG_ON(wakeups != (wakeups & VALID_WAKEUPS)); + + for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) { + if (wakeups & BIT(i)) + bits |= prcmu_wakeup_bit[i]; + } + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + mb0_transfer.req.dbb_wakeups = bits; + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +void prcmu_config_abb_event_readout(u32 abb_events) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + mb0_transfer.req.abb_events = abb_events; + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +void prcmu_get_abb_event_buffer(void __iomem **buf) +{ + if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) + *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500); + else + *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500); +} + +/** + * prcmu_set_arm_opp - set the appropriate ARM OPP + * @opp: The new ARM operating point to which transition is to be made + * Returns: 0 on success, non-zero on failure + * + * This function sets the the operating point of the ARM. + */ +int prcmu_set_arm_opp(u8 opp) +{ + int r; + + if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK) + return -EINVAL; + + r = 0; + + mutex_lock(&mb1_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); + writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); + + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || + (mb1_transfer.ack.arm_opp != opp)) + r = -EIO; + + mutex_unlock(&mb1_transfer.lock); + + return r; +} + +/** + * prcmu_get_arm_opp - get the current ARM OPP + * + * Returns: the current ARM OPP + */ +int prcmu_get_arm_opp(void) +{ + return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP); +} + +/** + * prcmu_get_ddr_opp - get the current DDR OPP + * + * Returns: the current DDR OPP + */ +int prcmu_get_ddr_opp(void) +{ + return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW); +} + +/** + * set_ddr_opp - set the appropriate DDR OPP + * @opp: The new DDR operating point to which transition is to be made + * Returns: 0 on success, non-zero on failure + * + * This function sets the operating point of the DDR. + */ +int prcmu_set_ddr_opp(u8 opp) +{ + if (opp < DDR_100_OPP || opp > DDR_25_OPP) + return -EINVAL; + /* Changing the DDR OPP can hang the hardware pre-v21 */ + if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20()) + writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW)); + + return 0; +} +/** + * set_ape_opp - set the appropriate APE OPP + * @opp: The new APE operating point to which transition is to be made + * Returns: 0 on success, non-zero on failure + * + * This function sets the operating point of the APE. + */ +int prcmu_set_ape_opp(u8 opp) +{ + int r = 0; + + mutex_lock(&mb1_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); + writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); + + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || + (mb1_transfer.ack.ape_opp != opp)) + r = -EIO; + + mutex_unlock(&mb1_transfer.lock); + + return r; +} + +/** + * prcmu_get_ape_opp - get the current APE OPP + * + * Returns: the current APE OPP + */ +int prcmu_get_ape_opp(void) +{ + return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP); +} + +/** + * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage + * @enable: true to request the higher voltage, false to drop a request. + * + * Calls to this function to enable and disable requests must be balanced. + */ +int prcmu_request_ape_opp_100_voltage(bool enable) +{ + int r = 0; + u8 header; + static unsigned int requests; + + mutex_lock(&mb1_transfer.lock); + + if (enable) { + if (0 != requests++) + goto unlock_and_return; + header = MB1H_REQUEST_APE_OPP_100_VOLT; + } else { + if (requests == 0) { + r = -EIO; + goto unlock_and_return; + } else if (1 != requests--) { + goto unlock_and_return; + } + header = MB1H_RELEASE_APE_OPP_100_VOLT; + } + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + if ((mb1_transfer.ack.header != header) || + ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) + r = -EIO; + +unlock_and_return: + mutex_unlock(&mb1_transfer.lock); + + return r; +} + +/** + * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup + * + * This function releases the power state requirements of a USB wakeup. + */ +int prcmu_release_usb_wakeup_state(void) +{ + int r = 0; + + mutex_lock(&mb1_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_RELEASE_USB_WAKEUP, + (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) || + ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) + r = -EIO; + + mutex_unlock(&mb1_transfer.lock); + + return r; +} + +static int request_pll(u8 clock, bool enable) +{ + int r = 0; + + if (clock == PRCMU_PLLSOC1) + clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF); + else + return -EINVAL; + + mutex_lock(&mb1_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_PLL_ON_OFF, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + writeb(clock, (tcdm_base + PRCM_REQ_MB1_PLL_ON_OFF)); + + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + if (mb1_transfer.ack.header != MB1H_PLL_ON_OFF) + r = -EIO; + + mutex_unlock(&mb1_transfer.lock); + + return r; +} + +/** + * prcmu_set_hwacc - set the power state of a h/w accelerator + * @hwacc_dev: The hardware accelerator (enum hw_acc_dev). + * @state: The new power state (enum hw_acc_state). + * + * This function sets the power state of a hardware accelerator. + * This function should not be called from interrupt context. + * + * NOTE! Deprecated, to be removed when all users switched over to use the + * regulator framework API. + */ +int prcmu_set_hwacc(u16 hwacc_dev, u8 state) +{ + int r = 0; + bool ram_retention = false; + bool enable, enable_ret; + + /* check argument */ + BUG_ON(hwacc_dev >= NUM_HW_ACC); + + /* get state of switches */ + enable = hwacc_enabled[hwacc_dev]; + enable_ret = hwacc_ret_enabled[hwacc_dev]; + + /* set flag if retention is possible */ + switch (hwacc_dev) { + case HW_ACC_SVAMMDSP: + case HW_ACC_SIAMMDSP: + case HW_ACC_ESRAM1: + case HW_ACC_ESRAM2: + case HW_ACC_ESRAM3: + case HW_ACC_ESRAM4: + ram_retention = true; + break; + } + + /* check argument */ + BUG_ON(state > HW_ON); + BUG_ON(state == HW_OFF_RAMRET && !ram_retention); + + /* modify enable flags */ + switch (state) { + case HW_OFF: + enable_ret = false; + enable = false; + break; + case HW_ON: + enable = true; + break; + case HW_OFF_RAMRET: + enable_ret = true; + enable = false; + break; + } + + /* get regulator (lazy) */ + if (hwacc_regulator[hwacc_dev] == NULL) { + hwacc_regulator[hwacc_dev] = regulator_get(NULL, + hwacc_regulator_name[hwacc_dev]); + if (IS_ERR(hwacc_regulator[hwacc_dev])) { + pr_err("prcmu: failed to get supply %s\n", + hwacc_regulator_name[hwacc_dev]); + r = PTR_ERR(hwacc_regulator[hwacc_dev]); + goto out; + } + } + + if (ram_retention) { + if (hwacc_ret_regulator[hwacc_dev] == NULL) { + hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL, + hwacc_ret_regulator_name[hwacc_dev]); + if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) { + pr_err("prcmu: failed to get supply %s\n", + hwacc_ret_regulator_name[hwacc_dev]); + r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]); + goto out; + } + } + } + + /* set regulators */ + if (ram_retention) { + if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) { + r = regulator_enable(hwacc_ret_regulator[hwacc_dev]); + if (r < 0) { + pr_err("prcmu_set_hwacc: ret enable failed\n"); + goto out; + } + hwacc_ret_enabled[hwacc_dev] = true; + } + } + + if (enable && !hwacc_enabled[hwacc_dev]) { + r = regulator_enable(hwacc_regulator[hwacc_dev]); + if (r < 0) { + pr_err("prcmu_set_hwacc: enable failed\n"); + goto out; + } + hwacc_enabled[hwacc_dev] = true; + } + + if (!enable && hwacc_enabled[hwacc_dev]) { + r = regulator_disable(hwacc_regulator[hwacc_dev]); + if (r < 0) { + pr_err("prcmu_set_hwacc: disable failed\n"); + goto out; + } + hwacc_enabled[hwacc_dev] = false; + } + + if (ram_retention) { + if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) { + r = regulator_disable(hwacc_ret_regulator[hwacc_dev]); + if (r < 0) { + pr_err("prcmu_set_hwacc: ret disable failed\n"); + goto out; + } + hwacc_ret_enabled[hwacc_dev] = false; + } + } + +out: + return r; +} +EXPORT_SYMBOL(prcmu_set_hwacc); + +/** + * prcmu_set_epod - set the state of a EPOD (power domain) + * @epod_id: The EPOD to set + * @epod_state: The new EPOD state + * + * This function sets the state of a EPOD (power domain). It may not be called + * from interrupt context. + */ +int prcmu_set_epod(u16 epod_id, u8 epod_state) +{ + int r = 0; + bool ram_retention = false; + int i; + + /* check argument */ + BUG_ON(epod_id >= NUM_EPOD_ID); + + /* set flag if retention is possible */ + switch (epod_id) { + case EPOD_ID_SVAMMDSP: + case EPOD_ID_SIAMMDSP: + case EPOD_ID_ESRAM12: + case EPOD_ID_ESRAM34: + ram_retention = true; + break; + } + + /* check argument */ + BUG_ON(epod_state > EPOD_STATE_ON); + BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); + + /* get lock */ + mutex_lock(&mb2_transfer.lock); + + /* wait for mailbox */ + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2)) + cpu_relax(); + + /* fill in mailbox */ + for (i = 0; i < NUM_EPOD_ID; i++) + writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i)); + writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id)); + + writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2)); + + writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + + /* + * The current firmware version does not handle errors correctly, + * and we cannot recover if there is an error. + * This is expected to change when the firmware is updated. + */ + if (!wait_for_completion_timeout(&mb2_transfer.work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + r = -EIO; + goto unlock_and_return; + } + + if (mb2_transfer.ack.status != HWACC_PWR_ST_OK) + r = -EIO; + +unlock_and_return: + mutex_unlock(&mb2_transfer.lock); + return r; +} + +/** + * prcmu_configure_auto_pm - Configure autonomous power management. + * @sleep: Configuration for ApSleep. + * @idle: Configuration for ApIdle. + */ +void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, + struct prcmu_auto_pm_config *idle) +{ + u32 sleep_cfg; + u32 idle_cfg; + unsigned long flags; + + BUG_ON((sleep == NULL) || (idle == NULL)); + + sleep_cfg = (sleep->sva_auto_pm_enable & 0xF); + sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF)); + sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF)); + sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF)); + sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF)); + sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF)); + + idle_cfg = (idle->sva_auto_pm_enable & 0xF); + idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF)); + idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF)); + idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF)); + idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF)); + idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF)); + + spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags); + + /* + * The autonomous power management configuration is done through + * fields in mailbox 2, but these fields are only used as shared + * variables - i.e. there is no need to send a message. + */ + writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP)); + writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE)); + + mb2_transfer.auto_pm_enabled = + ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || + (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) || + (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || + (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON)); + + spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags); +} +EXPORT_SYMBOL(prcmu_configure_auto_pm); + +bool prcmu_is_auto_pm_enabled(void) +{ + return mb2_transfer.auto_pm_enabled; +} + +static int request_sysclk(bool enable) +{ + int r; + unsigned long flags; + + r = 0; + + mutex_lock(&mb3_transfer.sysclk_lock); + + spin_lock_irqsave(&mb3_transfer.lock, flags); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3)) + cpu_relax(); + + writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT)); + + writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3)); + writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + + spin_unlock_irqrestore(&mb3_transfer.lock, flags); + + /* + * The firmware only sends an ACK if we want to enable the + * SysClk, and it succeeds. + */ + if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + r = -EIO; + } + + mutex_unlock(&mb3_transfer.sysclk_lock); + + return r; +} + +static int request_timclk(bool enable) +{ + u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); + + if (!enable) + val |= PRCM_TCR_STOP_TIMERS; + writel(val, (_PRCMU_BASE + PRCM_TCR)); + + return 0; +} + +static int request_reg_clock(u8 clock, bool enable) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&clk_mgt_lock, flags); + + /* Grab the HW semaphore. */ + while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) + cpu_relax(); + + val = readl(_PRCMU_BASE + clk_mgt[clock].offset); + if (enable) { + val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw); + } else { + clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK); + val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK); + } + writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); + + /* Release the HW semaphore. */ + writel(0, (_PRCMU_BASE + PRCM_SEM)); + + spin_unlock_irqrestore(&clk_mgt_lock, flags); + + return 0; +} + +/** + * prcmu_request_clock() - Request for a clock to be enabled or disabled. + * @clock: The clock for which the request is made. + * @enable: Whether the clock should be enabled (true) or disabled (false). + * + * This function should only be used by the clock implementation. + * Do not use it from any other place! + */ +int prcmu_request_clock(u8 clock, bool enable) +{ + if (clock < PRCMU_NUM_REG_CLOCKS) + return request_reg_clock(clock, enable); + else if (clock == PRCMU_TIMCLK) + return request_timclk(enable); + else if (clock == PRCMU_SYSCLK) + return request_sysclk(enable); + else if (clock == PRCMU_PLLSOC1) + return request_pll(clock, enable); + else + return -EINVAL; +} + +int prcmu_config_esram0_deep_sleep(u8 state) +{ + if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || + (state < ESRAM0_DEEP_SLEEP_STATE_OFF)) + return -EINVAL; + + mutex_lock(&mb4_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) + cpu_relax(); + + writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); + writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON), + (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE)); + writeb(DDR_PWR_STATE_ON, + (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE)); + writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST)); + + writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb4_transfer.work); + + mutex_unlock(&mb4_transfer.lock); + + return 0; +} + +int prcmu_config_hotdog(u8 threshold) +{ + mutex_lock(&mb4_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) + cpu_relax(); + + writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD)); + writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); + + writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb4_transfer.work); + + mutex_unlock(&mb4_transfer.lock); + + return 0; +} + +int prcmu_config_hotmon(u8 low, u8 high) +{ + mutex_lock(&mb4_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) + cpu_relax(); + + writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW)); + writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH)); + writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH), + (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG)); + writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); + + writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb4_transfer.work); + + mutex_unlock(&mb4_transfer.lock); + + return 0; +} + +static int config_hot_period(u16 val) +{ + mutex_lock(&mb4_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) + cpu_relax(); + + writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD)); + writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); + + writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb4_transfer.work); + + mutex_unlock(&mb4_transfer.lock); + + return 0; +} + +int prcmu_start_temp_sense(u16 cycles32k) +{ + if (cycles32k == 0xFFFF) + return -EINVAL; + + return config_hot_period(cycles32k); +} + +int prcmu_stop_temp_sense(void) +{ + return config_hot_period(0xFFFF); +} + +/** + * prcmu_set_clock_divider() - Configure the clock divider. + * @clock: The clock for which the request is made. + * @divider: The clock divider. (< 32) + * + * This function should only be used by the clock implementation. + * Do not use it from any other place! + */ +int prcmu_set_clock_divider(u8 clock, u8 divider) +{ + u32 val; + unsigned long flags; + + if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider)) + return -EINVAL; + + spin_lock_irqsave(&clk_mgt_lock, flags); + + /* Grab the HW semaphore. */ + while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) + cpu_relax(); + + val = readl(_PRCMU_BASE + clk_mgt[clock].offset); + val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK); + val |= (u32)divider; + writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); + + /* Release the HW semaphore. */ + writel(0, (_PRCMU_BASE + PRCM_SEM)); + + spin_unlock_irqrestore(&clk_mgt_lock, flags); + + return 0; +} + +/** + * 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; + + mutex_lock(&mb5_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) + cpu_relax(); + + writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); + writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); + writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); + writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); + + writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + + if (!wait_for_completion_timeout(&mb5_transfer.work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + r = -EIO; + } else { + r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO); + } + + if (!r) + *value = mb5_transfer.ack.value; + + mutex_unlock(&mb5_transfer.lock); + + return r; +} + +/** + * 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; + + mutex_lock(&mb5_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) + cpu_relax(); + + writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); + writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); + writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); + writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); + + writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + + if (!wait_for_completion_timeout(&mb5_transfer.work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + r = -EIO; + } else { + r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO); + } + + mutex_unlock(&mb5_transfer.lock); + + return r; +} + +/** + * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem + */ +void prcmu_ac_wake_req(void) +{ + u32 val; + + mutex_lock(&mb0_transfer.ac_wake_lock); + + val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); + if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ) + goto unlock_and_return; + + atomic_set(&ac_wake_req_state, 1); + + writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), + (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); + + if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + } + +unlock_and_return: + mutex_unlock(&mb0_transfer.ac_wake_lock); +} + +/** + * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem + */ +void prcmu_ac_sleep_req() +{ + u32 val; + + mutex_lock(&mb0_transfer.ac_wake_lock); + + val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); + if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)) + goto unlock_and_return; + + writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), + (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); + + if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + } + + atomic_set(&ac_wake_req_state, 0); + +unlock_and_return: + mutex_unlock(&mb0_transfer.ac_wake_lock); +} + +bool prcmu_is_ac_wake_requested(void) +{ + return (atomic_read(&ac_wake_req_state) != 0); +} + +/** + * prcmu_system_reset - System reset + * + * Saves the reset reason code and then sets the APE_SOFRST register which + * fires interrupt to fw + */ +void prcmu_system_reset(u16 reset_code) +{ + writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON)); + writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST)); +} + +/** + * prcmu_reset_modem - ask the PRCMU to reset modem + */ +void prcmu_modem_reset(void) +{ + mutex_lock(&mb1_transfer.lock); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); + wait_for_completion(&mb1_transfer.work); + + /* + * No need to check return from PRCMU as modem should go in reset state + * This state is already managed by upper layer + */ + + mutex_unlock(&mb1_transfer.lock); +} + +static void ack_dbb_wakeup(void) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) + cpu_relax(); + + writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); + writel(MBOX_BIT(0), (_PRCMU_BASE + 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; + u32 ev; + unsigned int n; + u8 header; + + header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0); + switch (header) { + case MB0H_WAKEUP_EXE: + case MB0H_WAKEUP_SLEEP: + if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) + ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500); + else + ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500); + + if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK)) + complete(&mb0_transfer.ac_wake_work); + if (ev & WAKEUP_BIT_SYSCLK_OK) + complete(&mb3_transfer.sysclk_work); + + ev &= mb0_transfer.req.dbb_irqs; + + for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) { + if (ev & prcmu_irq_bit[n]) + generic_handle_irq(IRQ_PRCMU_BASE + n); + } + r = true; + break; + default: + print_unknown_header_warning(0, header); + r = false; + break; + } + writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + return r; +} + +static bool read_mailbox_1(void) +{ + mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1); + mb1_transfer.ack.arm_opp = readb(tcdm_base + + PRCM_ACK_MB1_CURRENT_ARM_OPP); + mb1_transfer.ack.ape_opp = readb(tcdm_base + + PRCM_ACK_MB1_CURRENT_APE_OPP); + mb1_transfer.ack.ape_voltage_status = readb(tcdm_base + + PRCM_ACK_MB1_APE_VOLTAGE_STATUS); + writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + complete(&mb1_transfer.work); + return false; +} + +static bool read_mailbox_2(void) +{ + mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS); + writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + complete(&mb2_transfer.work); + return false; +} + +static bool read_mailbox_3(void) +{ + writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + return false; +} + +static bool read_mailbox_4(void) +{ + u8 header; + bool do_complete = true; + + header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4); + switch (header) { + case MB4H_MEM_ST: + case MB4H_HOTDOG: + case MB4H_HOTMON: + case MB4H_HOT_PERIOD: + break; + default: + print_unknown_header_warning(4, header); + do_complete = false; + break; + } + + writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + + if (do_complete) + complete(&mb4_transfer.work); + + return false; +} + +static bool read_mailbox_5(void) +{ + mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS); + mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL); + writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + complete(&mb5_transfer.work); + return false; +} + +static bool read_mailbox_6(void) +{ + writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + return false; +} + +static bool read_mailbox_7(void) +{ + writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + 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(_PRCMU_BASE + 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; +} + +static void prcmu_mask_work(struct work_struct *work) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +static void prcmu_irq_mask(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); + + mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[irq - IRQ_PRCMU_BASE]; + + spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); + + if (irq != IRQ_PRCMU_CA_SLEEP) + schedule_work(&mb0_transfer.mask_work); +} + +static void prcmu_irq_unmask(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); + + mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[irq - IRQ_PRCMU_BASE]; + + spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); + + if (irq != IRQ_PRCMU_CA_SLEEP) + schedule_work(&mb0_transfer.mask_work); +} + +static void noop(unsigned int irq) +{ +} + +static struct irq_chip prcmu_irq_chip = { + .name = "prcmu", + .disable = prcmu_irq_mask, + .ack = noop, + .mask = prcmu_irq_mask, + .unmask = prcmu_irq_unmask, +}; + +void __init prcmu_early_init(void) +{ + unsigned int i; + + if (cpu_is_u8500v1()) { + tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1); + } else if (cpu_is_u8500v2()) { + void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); + + if (tcpm_base != NULL) { + int version; + version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET); + prcmu_version.project_number = version & 0xFF; + prcmu_version.api_version = (version >> 8) & 0xFF; + prcmu_version.func_version = (version >> 16) & 0xFF; + prcmu_version.errata = (version >> 24) & 0xFF; + pr_info("PRCMU firmware version %d.%d.%d\n", + (version >> 8) & 0xFF, (version >> 16) & 0xFF, + (version >> 24) & 0xFF); + iounmap(tcpm_base); + } + + tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); + } else { + pr_err("prcmu: Unsupported chip version\n"); + BUG(); + } + + spin_lock_init(&mb0_transfer.lock); + spin_lock_init(&mb0_transfer.dbb_irqs_lock); + mutex_init(&mb0_transfer.ac_wake_lock); + init_completion(&mb0_transfer.ac_wake_work); + mutex_init(&mb1_transfer.lock); + init_completion(&mb1_transfer.work); + mutex_init(&mb2_transfer.lock); + init_completion(&mb2_transfer.work); + spin_lock_init(&mb2_transfer.auto_pm_lock); + spin_lock_init(&mb3_transfer.lock); + mutex_init(&mb3_transfer.sysclk_lock); + init_completion(&mb3_transfer.sysclk_work); + mutex_init(&mb4_transfer.lock); + init_completion(&mb4_transfer.work); + mutex_init(&mb5_transfer.lock); + init_completion(&mb5_transfer.work); + + INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); + + /* Initalize irqs. */ + for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { + unsigned int irq; + + irq = IRQ_PRCMU_BASE + i; + set_irq_chip(irq, &prcmu_irq_chip); + set_irq_flags(irq, IRQF_VALID); + set_irq_handler(irq, handle_simple_irq); + } +} + +/** + * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic + * + */ +int __init prcmu_init(void) +{ + int err = 0; + + if (ux500_is_svp()) + return -ENODEV; + + /* Clean up the mailbox interrupts after pre-kernel code. */ + writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); + + err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, + prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); + if (err < 0) { + pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n"); + err = -EBUSY; + goto no_irq_return; + } + + prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); + + if (prcmu_debug_init()) + pr_err("prcmu: Failed to initialize debugfs\n"); + +no_irq_return: + return err; +} + +arch_initcall(prcmu_init); diff --git a/arch/arm/mach-ux500/prcmu-debug.c b/arch/arm/mach-ux500/prcmu-debug.c new file mode 100644 index 00000000000..0e45a2309d0 --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-debug.c @@ -0,0 +1,503 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * + * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson + * Etienne Carriere <etienne.carriere@stericsson.com> for ST-Ericsson + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#include <mach/prcmu-fw-api.h> + +enum ape_opp_debug { + APE_50_OPP_DEBUG, + APE_100_OPP_DEBUG, + NUM_APE_OPP_DEBUG, +}; + +enum ddr_opp_debug { + DDR_25_OPP_DEBUG, + DDR_50_OPP_DEBUG, + DDR_100_OPP_DEBUG, + NUM_DDR_OPP_DEBUG, +}; + +struct ape_state_history { + ktime_t start; + u32 state; + u32 counter[NUM_APE_OPP_DEBUG]; + ktime_t time[NUM_APE_OPP_DEBUG]; + spinlock_t lock; +}; + +struct ddr_state_history { + ktime_t start; + u32 state; + u32 counter[NUM_DDR_OPP_DEBUG]; + ktime_t time[NUM_DDR_OPP_DEBUG]; + spinlock_t lock; +}; + +static struct ape_state_history *ape_sh; +static struct ddr_state_history *ddr_sh; + +void prcmu_debug_ape_opp_log(u8 opp) +{ + ktime_t now; + ktime_t dtime; + unsigned long flags; + int state; + + if (opp == APE_50_OPP) + state = APE_50_OPP_DEBUG; + else + state = APE_100_OPP_DEBUG; + + now = ktime_get(); + spin_lock_irqsave(&ape_sh->lock, flags); + + dtime = ktime_sub(now, ape_sh->start); + ape_sh->time[state] = ktime_add(ape_sh->time[state], dtime); + ape_sh->start = now; + ape_sh->counter[state]++; + ape_sh->state = state; + + spin_unlock_irqrestore(&ape_sh->lock, flags); +} + +void prcmu_debug_ddr_opp_log(u8 opp) +{ + ktime_t now; + ktime_t dtime; + unsigned long flags; + int state; + + if (opp == DDR_25_OPP) + state = DDR_25_OPP_DEBUG; + else if (opp == DDR_50_OPP) + state = DDR_50_OPP_DEBUG; + else + state = DDR_100_OPP_DEBUG; + + now = ktime_get(); + spin_lock_irqsave(&ddr_sh->lock, flags); + + dtime = ktime_sub(now, ddr_sh->start); + ddr_sh->time[state] = ktime_add(ddr_sh->time[state], dtime); + ddr_sh->start = now; + ddr_sh->counter[state]++; + ddr_sh->state = state; + + spin_unlock_irqrestore(&ddr_sh->lock, flags); +} + +static ssize_t ape_stats_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + unsigned long flags; + int i; + + pr_info("/nreset\n"); + + spin_lock_irqsave(&ape_sh->lock, flags); + for (i = 0; i < NUM_APE_OPP_DEBUG; i++) { + ape_sh->counter[i] = 0; + ape_sh->time[i] = ktime_set(0, 0); + } + + ape_sh->start = ktime_get(); + spin_unlock_irqrestore(&ape_sh->lock, flags); + + return count; +} + +static ssize_t ddr_stats_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + unsigned long flags; + int i; + + pr_info("/nreset\n"); + + spin_lock_irqsave(&ddr_sh->lock, flags); + for (i = 0; i < NUM_DDR_OPP_DEBUG; i++) { + ddr_sh->counter[i] = 0; + ddr_sh->time[i] = ktime_set(0, 0); + } + + ddr_sh->start = ktime_get(); + spin_unlock_irqrestore(&ddr_sh->lock, flags); + + return count; +} + +static int ape_stats_print(struct seq_file *s, void *p) +{ + int i; + unsigned long flags; + ktime_t total; + ktime_t now; + ktime_t dtime; + s64 t_us; + s64 perc; + s64 total_us; + + spin_lock_irqsave(&ape_sh->lock, flags); + /* Update time in state */ + now = ktime_get(); + dtime = ktime_sub(now, ape_sh->start); + ape_sh->time[ape_sh->state] = + ktime_add(ape_sh->time[ape_sh->state], dtime); + ape_sh->start = now; + + /* Now print the stats */ + total = ktime_set(0, 0); + + for (i = 0; i < NUM_APE_OPP_DEBUG; i++) + total = ktime_add(total, ape_sh->time[i]); + total_us = ktime_to_us(total); + do_div(total_us, 100); + + for (i = 0; i < NUM_APE_OPP_DEBUG; i++) { + t_us = ktime_to_us(ape_sh->time[i]); + perc = ktime_to_us(ape_sh->time[i]); + do_div(t_us, 1000); /* to ms */ + do_div(perc, total_us); + if (i == APE_50_OPP_DEBUG) + seq_printf(s, "%s: # %u in %d ms %d%%\n", + "APE OPP 50% ", + ape_sh->counter[i], + (u32) t_us, (u32)perc); + else + seq_printf(s, "%s: # %u in %d ms %d%%\n", + "APE OPP 100%", + ape_sh->counter[i], + (u32) t_us, (u32)perc); + + } + spin_unlock_irqrestore(&ape_sh->lock, flags); + return 0; +} + +static int ddr_stats_print(struct seq_file *s, void *p) +{ + int i; + unsigned long flags; + ktime_t total; + ktime_t now; + ktime_t dtime; + s64 t_us; + s64 perc; + s64 total_us; + + spin_lock_irqsave(&ddr_sh->lock, flags); + /* Update time in state */ + now = ktime_get(); + dtime = ktime_sub(now, ddr_sh->start); + ddr_sh->time[ddr_sh->state] = + ktime_add(ddr_sh->time[ddr_sh->state], dtime); + ddr_sh->start = now; + + /* Now print the stats */ + total = ktime_set(0, 0); + + for (i = 0; i < NUM_DDR_OPP_DEBUG; i++) + total = ktime_add(total, ddr_sh->time[i]); + total_us = ktime_to_us(total); + do_div(total_us, 100); + + for (i = 0; i < NUM_DDR_OPP_DEBUG; i++) { + t_us = ktime_to_us(ddr_sh->time[i]); + perc = ktime_to_us(ddr_sh->time[i]); + do_div(t_us, 1000); /* to ms */ + do_div(perc, total_us); + if (i == DDR_25_OPP_DEBUG) + seq_printf(s, "%s: # %u in %d ms %d%%\n", + "DDR OPP 25% ", + ddr_sh->counter[i], + (u32) t_us, (u32)perc); + else if (i == DDR_50_OPP_DEBUG) + seq_printf(s, "%s: # %u in %d ms %d%%\n", + "DDR OPP 50% ", + ddr_sh->counter[i], + (u32) t_us, (u32)perc); + else + seq_printf(s, "%s: # %u in %d ms %d%%\n", + "DDR OPP 100%", + ddr_sh->counter[i], + (u32) t_us, (u32)perc); + + } + spin_unlock_irqrestore(&ddr_sh->lock, flags); + return 0; +} + +static int arm_opp_read(struct seq_file *s, void *p) +{ + int opp; + + opp = prcmu_get_arm_opp(); + return seq_printf(s, "%s (%d)\n", + (opp == ARM_MAX_OPP) ? "max" : + (opp == ARM_MAX_FREQ100OPP) ? "max-freq100" : + (opp == ARM_100_OPP) ? "100%" : + (opp == ARM_50_OPP) ? "50%" : + (opp == ARM_EXTCLK) ? "25% (extclk)" : + "unknown", opp); +} + +static int ape_opp_read(struct seq_file *s, void *p) +{ + int opp; + + opp = prcmu_get_ape_opp(); + return seq_printf(s, "%s (%d)\n", + (opp == APE_100_OPP) ? "100%" : + (opp == APE_50_OPP) ? "50%" : + "unknown", opp); +} + +static int ddr_opp_read(struct seq_file *s, void *p) +{ + int opp; + + opp = prcmu_get_ddr_opp(); + return seq_printf(s, "%s (%d)\n", + (opp == DDR_100_OPP) ? "100%" : + (opp == DDR_50_OPP) ? "50%" : + (opp == DDR_25_OPP) ? "25%" : + "unknown", opp); +} + +static ssize_t opp_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos, int prcmu_qos_class) +{ + char buf[32]; + ssize_t buf_size; + long unsigned int i; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (strict_strtoul(buf, 0, &i) != 0) + return buf_size; + + prcmu_qos_force_opp(prcmu_qos_class, i); + + pr_info("prcmu debug: forced OPP for %d to %d\n", prcmu_qos_class, (int)i); + + return buf_size; +} + +static ssize_t ddr_opp_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + return opp_write(file, user_buf, count, ppos, PRCMU_QOS_DDR_OPP); +} + +static ssize_t ape_opp_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + return opp_write(file, user_buf, count, ppos, PRCMU_QOS_APE_OPP); +} + +static int cpufreq_delay_read(struct seq_file *s, void *p) +{ + return seq_printf(s, "%lu\n", prcmu_qos_get_cpufreq_opp_delay()); +} + +static ssize_t cpufreq_delay_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + + char buf[32]; + ssize_t buf_size; + long unsigned int i; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (strict_strtoul(buf, 0, &i) != 0) + return buf_size; + + prcmu_qos_set_cpufreq_opp_delay(i); + + pr_info("prcmu debug: changed delay between cpufreq change and QoS " + "requirement to %lu.\n", i); + + return buf_size; +} + +static int arm_opp_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, arm_opp_read, inode->i_private); +} + +static int ape_opp_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, ape_opp_read, inode->i_private); +} + +static int ddr_opp_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, ddr_opp_read, inode->i_private); +} + +static int ape_stats_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, ape_stats_print, inode->i_private); +} + +static int ddr_stats_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, ddr_stats_print, inode->i_private); +} + +static int cpufreq_delay_open_file(struct inode *inode, struct file *file) +{ + return single_open(file, cpufreq_delay_read, inode->i_private); +} + +static const struct file_operations arm_opp_fops = { + .open = arm_opp_open_file, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ape_opp_fops = { + .open = ape_opp_open_file, + .write = ape_opp_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ddr_opp_fops = { + .open = ddr_opp_open_file, + .write = ddr_opp_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ape_stats_fops = { + .open = ape_stats_open_file, + .write = ape_stats_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ddr_stats_fops = { + .open = ddr_stats_open_file, + .write = ddr_stats_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations cpufreq_delay_fops = { + .open = cpufreq_delay_open_file, + .write = cpufreq_delay_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int setup_debugfs(void) +{ + struct dentry *dir; + struct dentry *file; + + dir = debugfs_create_dir("prcmu", NULL); + if (IS_ERR_OR_NULL(dir)) + goto fail; + + file = debugfs_create_file("ape_stats", (S_IRUGO | S_IWUGO), + dir, NULL, &ape_stats_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + file = debugfs_create_file("ddr_stats", (S_IRUGO | S_IWUGO), + dir, NULL, &ddr_stats_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + file = debugfs_create_file("ape_opp", (S_IRUGO), + dir, NULL, &ape_opp_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + file = debugfs_create_file("ddr_opp", (S_IRUGO), + dir, NULL, &ddr_opp_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + file = debugfs_create_file("arm_opp", (S_IRUGO), + dir, NULL, &arm_opp_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + file = debugfs_create_file("opp_cpufreq_delay", (S_IRUGO), + dir, NULL, &cpufreq_delay_fops); + if (IS_ERR_OR_NULL(file)) + goto fail; + + return 0; +fail: + if ((file == NULL) && (dir != NULL)) + debugfs_remove_recursive(dir); + + pr_err("prcmu debug: debugfs entry failed\n"); + return -ENOMEM; +} + +int prcmu_debug_init(void) +{ + ape_sh = kzalloc(sizeof(struct ape_state_history), GFP_KERNEL); + if (ape_sh < 0) { + pr_err("prcmu debug: kzalloc failed\n"); + return -ENOMEM; + } + + ddr_sh = kzalloc(sizeof(struct ddr_state_history), GFP_KERNEL); + if (ddr_sh < 0) { + pr_err("prcmu debug: kzalloc failed\n"); + return -ENOMEM; + } + + spin_lock_init(&ape_sh->lock); + spin_lock_init(&ddr_sh->lock); + ape_sh->start = ktime_get(); + ddr_sh->start = ktime_get(); + setup_debugfs(); + return 0; +} diff --git a/arch/arm/mach-ux500/prcmu-debug.h b/arch/arm/mach-ux500/prcmu-debug.h new file mode 100644 index 00000000000..c536aed1f6b --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-debug.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * + * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson + * Etienne Carriere <etienne.carriere@stericsson.com> for ST-Ericsson + * + */ + +#ifndef PRCMU_DEBUG_H +#define PRCMU_DEBUG_H + +#ifdef CONFIG_UX500_PRCMU_DEBUG +void prcmu_debug_ape_opp_log(u8 opp); +void prcmu_debug_ddr_opp_log(u8 opp); +int prcmu_debug_init(void); +#else +static inline void prcmu_debug_ape_opp_log(u8 opp) {} +static inline void prcmu_debug_ddr_opp_log(u8 opp) {} +static inline int prcmu_debug_init(void) {} +#endif +#endif diff --git a/arch/arm/mach-ux500/prcmu-qos-power.c b/arch/arm/mach-ux500/prcmu-qos-power.c new file mode 100644 index 00000000000..c7fa4160f62 --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-qos-power.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * Author: Martin Persson <martin.persson@stericsson.com> + * Per Fransson <per.xx.fransson@stericsson.com> + * + * Quality of Service for the U8500 PRCM Unit interface driver + * + * Strongly influenced by kernel/pm_qos_params.c. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/cpufreq.h> + +#include "prcmu-debug.h" +#include <mach/prcmu-fw-api.h> + +#define ARM_THRESHOLD_FREQ (400000) + +static int qos_delayed_cpufreq_notifier(struct notifier_block *, + unsigned long, void *); + +static s32 cpufreq_requirement_queued; +static s32 cpufreq_requirement_set; + +/* + * locking rule: all changes to requirements or prcmu_qos_object list + * and prcmu_qos_objects need to happen with prcmu_qos_lock + * held, taken with _irqsave. One lock to rule them all + */ +struct requirement_list { + struct list_head list; + union { + s32 value; + s32 usec; + s32 kbps; + }; + char *name; +}; + +static s32 max_compare(s32 v1, s32 v2); + +struct prcmu_qos_object { + struct requirement_list requirements; + struct blocking_notifier_head *notifiers; + struct miscdevice prcmu_qos_power_miscdev; + char *name; + s32 default_value; + s32 force_value; + atomic_t target_value; + s32 (*comparitor)(s32, s32); +}; + +static struct prcmu_qos_object null_qos; +static BLOCKING_NOTIFIER_HEAD(prcmu_ape_opp_notifier); +static BLOCKING_NOTIFIER_HEAD(prcmu_ddr_opp_notifier); + +static struct prcmu_qos_object ape_opp_qos = { + .requirements = { + LIST_HEAD_INIT(ape_opp_qos.requirements.list) + }, + .notifiers = &prcmu_ape_opp_notifier, + .name = "ape_opp", + /* Target value in % APE OPP */ + .default_value = 50, + .force_value = 0, + .target_value = ATOMIC_INIT(0), + .comparitor = max_compare +}; + +static struct prcmu_qos_object ddr_opp_qos = { + .requirements = { + LIST_HEAD_INIT(ddr_opp_qos.requirements.list) + }, + .notifiers = &prcmu_ddr_opp_notifier, + .name = "ddr_opp", + /* Target value in % DDR OPP */ + .default_value = 25, + .force_value = 0, + .target_value = ATOMIC_INIT(0), + .comparitor = max_compare +}; + +static struct prcmu_qos_object *prcmu_qos_array[] = { + &null_qos, + &ape_opp_qos, + &ddr_opp_qos +}; + +static DEFINE_SPINLOCK(prcmu_qos_lock); + +static unsigned long cpufreq_opp_delay = HZ / 5; + +unsigned long prcmu_qos_get_cpufreq_opp_delay() +{ + return cpufreq_opp_delay; +} + +static struct notifier_block qos_delayed_cpufreq_notifier_block = { + .notifier_call = qos_delayed_cpufreq_notifier, +}; + +void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) +{ + if (n == 0) { + cpufreq_unregister_notifier(&qos_delayed_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + prcmu_qos_update_requirement(PRCMU_QOS_DDR_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + cpufreq_requirement_set = PRCMU_QOS_DEFAULT_VALUE; + cpufreq_requirement_queued = PRCMU_QOS_DEFAULT_VALUE; + } else if (cpufreq_opp_delay != 0) { + cpufreq_register_notifier(&qos_delayed_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + cpufreq_opp_delay = n; +} + +/* static helper function */ +static s32 max_compare(s32 v1, s32 v2) +{ + return max(v1, v2); +} + +static void update_target(int target) +{ + s32 extreme_value; + struct requirement_list *node; + unsigned long flags; + int update = 0; + u8 op; + + spin_lock_irqsave(&prcmu_qos_lock, flags); + extreme_value = prcmu_qos_array[target]->default_value; + + if (prcmu_qos_array[target]->force_value != 0) { + extreme_value = prcmu_qos_array[target]->force_value; + update = 1; + } else { + list_for_each_entry(node, + &prcmu_qos_array[target]->requirements.list, + list) { + extreme_value = prcmu_qos_array[target]->comparitor( + extreme_value, node->value); + } + if (atomic_read(&prcmu_qos_array[target]->target_value) + != extreme_value) { + update = 1; + atomic_set(&prcmu_qos_array[target]->target_value, + extreme_value); + pr_debug("prcmu qos: new target for qos %d is %d\n", + target, atomic_read( + &prcmu_qos_array[target]->target_value + )); + } + } + spin_unlock_irqrestore(&prcmu_qos_lock, flags); + + if (update) { + blocking_notifier_call_chain(prcmu_qos_array[target]->notifiers, + (unsigned long)extreme_value, NULL); + + if (target == PRCMU_QOS_DDR_OPP) { + switch (extreme_value) { + case 25: + op = DDR_25_OPP; + pr_debug("prcmu qos: set ddr opp to 25%%\n"); + break; + case 50: + op = DDR_50_OPP; + pr_debug("prcmu qos: set ddr opp to 50%%\n"); + break; + case 100: + op = DDR_100_OPP; + pr_debug("prcmu qos: set ddr opp to 100%%\n"); + break; + default: + pr_err("prcmu qos: Incorrect ddr target value (%d)", + extreme_value); + return; + } + prcmu_debug_ddr_opp_log(op); + prcmu_set_ddr_opp(op); + } else { + switch (extreme_value) { + case 50: + op = APE_50_OPP; + pr_debug("prcmu qos: set ape opp to 50%%\n"); + break; + case 100: + op = APE_100_OPP; + pr_debug("prcmu qos: set ape opp to 100%%\n"); + break; + default: + pr_err("prcmu qos: Incorrect ape target value (%d)", + extreme_value); + return; + } + prcmu_set_ape_opp(op); + prcmu_debug_ape_opp_log(op); + } + } +} + +void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) +{ + prcmu_qos_array[prcmu_qos_class]->force_value = i; + update_target(prcmu_qos_class); +} + +/** + * prcmu_qos_requirement - returns current prcmu qos expectation + * @prcmu_qos_class: identification of which qos value is requested + * + * This function returns the current target value in an atomic manner. + */ +int prcmu_qos_requirement(int prcmu_qos_class) +{ + return atomic_read(&prcmu_qos_array[prcmu_qos_class]->target_value); +} +EXPORT_SYMBOL_GPL(prcmu_qos_requirement); + +/** + * prcmu_qos_add_requirement - inserts new qos request into the list + * @prcmu_qos_class: identifies which list of qos request to us + * @name: identifies the request + * @value: defines the qos request + * + * This function inserts a new entry in the prcmu_qos_class list of requested + * qos performance characteristics. It recomputes the aggregate QoS + * expectations for the prcmu_qos_class of parameters. + */ +int prcmu_qos_add_requirement(int prcmu_qos_class, char *name, s32 value) +{ + struct requirement_list *dep; + unsigned long flags; + + dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL); + if (dep < 0) + return -ENOMEM; + + if (value == PRCMU_QOS_DEFAULT_VALUE) + dep->value = prcmu_qos_array[prcmu_qos_class]->default_value; + else + dep->value = value; + dep->name = kstrdup(name, GFP_KERNEL); + if (!dep->name) + goto cleanup; + + spin_lock_irqsave(&prcmu_qos_lock, flags); + list_add(&dep->list, + &prcmu_qos_array[prcmu_qos_class]->requirements.list); + spin_unlock_irqrestore(&prcmu_qos_lock, flags); + update_target(prcmu_qos_class); + + return 0; + +cleanup: + kfree(dep); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(prcmu_qos_add_requirement); + +/** + * prcmu_qos_update_requirement - modifies an existing qos request + * @prcmu_qos_class: identifies which list of qos request to us + * @name: identifies the request + * @value: defines the qos request + * + * Updates an existing qos requirement for the prcmu_qos_class of parameters + * along with updating the target prcmu_qos_class value. + * + * If the named request isn't in the list then no change is made. + */ +int prcmu_qos_update_requirement(int prcmu_qos_class, char *name, s32 new_value) +{ + unsigned long flags; + struct requirement_list *node; + int pending_update = 0; + + spin_lock_irqsave(&prcmu_qos_lock, flags); + list_for_each_entry(node, + &prcmu_qos_array[prcmu_qos_class]->requirements.list, list) { + if (strcmp(node->name, name) == 0) { + if (new_value == PRCMU_QOS_DEFAULT_VALUE) + node->value = + prcmu_qos_array[prcmu_qos_class]->default_value; + else + node->value = new_value; + pending_update = 1; + break; + } + } + spin_unlock_irqrestore(&prcmu_qos_lock, flags); + if (pending_update) + update_target(prcmu_qos_class); + + return 0; +} +EXPORT_SYMBOL_GPL(prcmu_qos_update_requirement); + +/** + * prcmu_qos_remove_requirement - modifies an existing qos request + * @prcmu_qos_class: identifies which list of qos request to us + * @name: identifies the request + * + * Will remove named qos request from prcmu_qos_class list of parameters and + * recompute the current target value for the prcmu_qos_class. + */ +void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name) +{ + unsigned long flags; + struct requirement_list *node; + int pending_update = 0; + + spin_lock_irqsave(&prcmu_qos_lock, flags); + list_for_each_entry(node, + &prcmu_qos_array[prcmu_qos_class]->requirements.list, list) { + if (strcmp(node->name, name) == 0) { + kfree(node->name); + list_del(&node->list); + kfree(node); + pending_update = 1; + break; + } + } + spin_unlock_irqrestore(&prcmu_qos_lock, flags); + if (pending_update) + update_target(prcmu_qos_class); +} +EXPORT_SYMBOL_GPL(prcmu_qos_remove_requirement); + +/** + * prcmu_qos_add_notifier - sets notification entry for changes to target value + * @prcmu_qos_class: identifies which qos target changes should be notified. + * @notifier: notifier block managed by caller. + * + * will register the notifier into a notification chain that gets called + * upon changes to the prcmu_qos_class target value. + */ +int prcmu_qos_add_notifier(int prcmu_qos_class, struct notifier_block *notifier) +{ + int retval; + + retval = blocking_notifier_chain_register( + prcmu_qos_array[prcmu_qos_class]->notifiers, notifier); + + return retval; +} +EXPORT_SYMBOL_GPL(prcmu_qos_add_notifier); + +/** + * prcmu_qos_remove_notifier - deletes notification entry from chain. + * @prcmu_qos_class: identifies which qos target changes are notified. + * @notifier: notifier block to be removed. + * + * will remove the notifier from the notification chain that gets called + * upon changes to the prcmu_qos_class target value. + */ +int prcmu_qos_remove_notifier(int prcmu_qos_class, + struct notifier_block *notifier) +{ + int retval; + + retval = blocking_notifier_chain_unregister( + prcmu_qos_array[prcmu_qos_class]->notifiers, notifier); + + return retval; +} +EXPORT_SYMBOL_GPL(prcmu_qos_remove_notifier); + +#define USER_QOS_NAME_LEN 32 + +static int prcmu_qos_power_open(struct inode *inode, struct file *filp, + long prcmu_qos_class) +{ + int ret; + char name[USER_QOS_NAME_LEN]; + + filp->private_data = (void *)prcmu_qos_class; + snprintf(name, USER_QOS_NAME_LEN, "file_%08x", (unsigned int)filp); + ret = prcmu_qos_add_requirement(prcmu_qos_class, name, + PRCMU_QOS_DEFAULT_VALUE); + if (ret >= 0) + return 0; + + return -EPERM; +} + + +static int prcmu_qos_ape_power_open(struct inode *inode, struct file *filp) +{ + return prcmu_qos_power_open(inode, filp, PRCMU_QOS_APE_OPP); +} + +static int prcmu_qos_ddr_power_open(struct inode *inode, struct file *filp) +{ + return prcmu_qos_power_open(inode, filp, PRCMU_QOS_DDR_OPP); +} + +static int prcmu_qos_power_release(struct inode *inode, struct file *filp) +{ + int prcmu_qos_class; + char name[USER_QOS_NAME_LEN]; + + prcmu_qos_class = (long)filp->private_data; + snprintf(name, USER_QOS_NAME_LEN, "file_%08x", (unsigned int)filp); + prcmu_qos_remove_requirement(prcmu_qos_class, name); + + return 0; +} + +static ssize_t prcmu_qos_power_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + s32 value; + int prcmu_qos_class; + char name[USER_QOS_NAME_LEN]; + + prcmu_qos_class = (long)filp->private_data; + if (count != sizeof(s32)) + return -EINVAL; + if (copy_from_user(&value, buf, sizeof(s32))) + return -EFAULT; + snprintf(name, USER_QOS_NAME_LEN, "file_%08x", (unsigned int)filp); + prcmu_qos_update_requirement(prcmu_qos_class, name, value); + + return sizeof(s32); +} + +/* Functions to provide QoS to user space */ +static const struct file_operations prcmu_qos_ape_power_fops = { + .write = prcmu_qos_power_write, + .open = prcmu_qos_ape_power_open, + .release = prcmu_qos_power_release, +}; + +/* Functions to provide QoS to user space */ +static const struct file_operations prcmu_qos_ddr_power_fops = { + .write = prcmu_qos_power_write, + .open = prcmu_qos_ddr_power_open, + .release = prcmu_qos_power_release, +}; + +static int register_prcmu_qos_misc(struct prcmu_qos_object *qos, + const struct file_operations *fops) +{ + qos->prcmu_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; + qos->prcmu_qos_power_miscdev.name = qos->name; + qos->prcmu_qos_power_miscdev.fops = fops; + + return misc_register(&qos->prcmu_qos_power_miscdev); +} + +static void qos_delayed_work_up_fn(struct work_struct *work) +{ + prcmu_qos_update_requirement(PRCMU_QOS_DDR_OPP, "cpufreq", 100); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "cpufreq", 100); + cpufreq_requirement_set = 100; +} + +static void qos_delayed_work_down_fn(struct work_struct *work) +{ + prcmu_qos_update_requirement(PRCMU_QOS_DDR_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + cpufreq_requirement_set = PRCMU_QOS_DEFAULT_VALUE; +} + +static DECLARE_DELAYED_WORK(qos_delayed_work_up, qos_delayed_work_up_fn); +static DECLARE_DELAYED_WORK(qos_delayed_work_down, qos_delayed_work_down_fn); + +static int qos_delayed_cpufreq_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct cpufreq_freqs *freq = data; + s32 new_ddr_target; + + /* Only react once per transition and only for one core, e.g. core 0 */ + if (event != CPUFREQ_POSTCHANGE || freq->cpu != 0) + return 0; + + /* + * APE and DDR OPP are always handled together in this solution. + * Hence no need to check both DDR and APE opp in the code below. + */ + + /* Which DDR OPP are we aiming for? */ + if (freq->new > ARM_THRESHOLD_FREQ) + new_ddr_target = 100; + else + new_ddr_target = PRCMU_QOS_DEFAULT_VALUE; + + if (new_ddr_target == cpufreq_requirement_queued) { + /* + * We're already at, or going to, the target requirement. + * This is only a fluctuation within the interval + * corresponding to the same DDR requirement. + */ + return 0; + } + cpufreq_requirement_queued = new_ddr_target; + + if (freq->new > ARM_THRESHOLD_FREQ) { + cancel_delayed_work_sync(&qos_delayed_work_down); + /* + * Only schedule this requirement if it is not the current + * one. + */ + if (new_ddr_target != cpufreq_requirement_set) + schedule_delayed_work(&qos_delayed_work_up, + cpufreq_opp_delay); + } else { + cancel_delayed_work_sync(&qos_delayed_work_up); + /* + * Only schedule this requirement if it is not the current + * one. + */ + if (new_ddr_target != cpufreq_requirement_set) + schedule_delayed_work(&qos_delayed_work_down, + cpufreq_opp_delay); + } + + return 0; +} + +static int __init prcmu_qos_power_init(void) +{ + int ret = 0; + + ret = register_prcmu_qos_misc(&ape_opp_qos, &prcmu_qos_ape_power_fops); + if (ret < 0) { + pr_err("prcmu ape qos: setup failed\n"); + return ret; + } + + ret = register_prcmu_qos_misc(&ddr_opp_qos, &prcmu_qos_ddr_power_fops); + if (ret < 0) { + pr_err("prcmu ddr qos: setup failed\n"); + return ret; + } + + prcmu_qos_add_requirement(PRCMU_QOS_DDR_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, "cpufreq", + PRCMU_QOS_DEFAULT_VALUE); + cpufreq_requirement_set = PRCMU_QOS_DEFAULT_VALUE; + cpufreq_requirement_queued = PRCMU_QOS_DEFAULT_VALUE; + + cpufreq_register_notifier(&qos_delayed_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + + return ret; +} + +late_initcall(prcmu_qos_power_init); diff --git a/arch/arm/mach-ux500/prcmu-regs-db5500.h b/arch/arm/mach-ux500/prcmu-regs-db5500.h new file mode 100644 index 00000000000..c18e482d136 --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-regs-db5500.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ + +#ifndef __MACH_PRCMU_REGS_DB5500_H +#define __MACH_PRCMU_REGS_DB5500_H + +#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end)) + +#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) + +/* PRCMU HW semaphore */ +#define PRCM_SEM 0x400 +#define PRCM_SEM_PRCM_SEM BIT(0) + +#define DB5500_PRCM_SGACLK_MGT 0x014 +#define DB5500_PRCM_UARTCLK_MGT 0x018 +#define DB5500_PRCM_MSP02CLK_MGT 0x01C +#define DB5500_PRCM_I2CCLK_MGT 0x020 +#define DB5500_PRCM_SDMMCCLK_MGT 0x024 +#define DB5500_PRCM_PER1CLK_MGT 0x02C +#define DB5500_PRCM_PER2CLK_MGT 0x030 +#define DB5500_PRCM_PER3CLK_MGT 0x034 +#define DB5500_PRCM_PER5CLK_MGT 0x038 +#define DB5500_PRCM_PER6CLK_MGT 0x03C +#define DB5500_PRCM_PWMCLK_MGT 0x044 +#define DB5500_PRCM_IRDACLK_MGT 0x048 +#define DB5500_PRCM_IRRCCLK_MGT 0x04C +#define DB5500_PRCM_HDMICLK_MGT 0x058 +#define DB5500_PRCM_APEATCLK_MGT 0x05C +#define DB5500_PRCM_APETRACECLK_MGT 0x060 +#define DB5500_PRCM_MCDECLK_MGT 0x064 +#define DB5500_PRCM_DSIALTCLK_MGT 0x06C +#define DB5500_PRCM_DMACLK_MGT 0x074 +#define DB5500_PRCM_B2R2CLK_MGT 0x078 +#define DB5500_PRCM_TVCLK_MGT 0x07C +#define DB5500_PRCM_RNGCLK_MGT 0x284 + +#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) + +#endif diff --git a/arch/arm/mach-ux500/prcmu-regs-db8500.h b/arch/arm/mach-ux500/prcmu-regs-db8500.h new file mode 100644 index 00000000000..7ae1218f6ba --- /dev/null +++ b/arch/arm/mach-ux500/prcmu-regs-db8500.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2009 ST-Ericsson SA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ +#ifndef __MACH_PRCMU_REGS_H +#define __MACH_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 /* __MACH_PRCMU__REGS_H */ diff --git a/arch/arm/mach-ux500/pwm.c b/arch/arm/mach-ux500/pwm.c new file mode 100644 index 00000000000..37f6bd481c5 --- /dev/null +++ b/arch/arm/mach-ux500/pwm.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for + * ST-Ericsson. + * Author: Magnus Templing <magnus.templing@stericsson.com> for + * ST-Ericsson. + * + * PWM (Pulse Width Modulator) driver for the DB5500 digital baseband + * controller. Based on arch/arm/mach-pxa/pwm.c. + */ +#include <linux/err.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +/* Register offsets */ +#define PWM_CONTROL_REG_OFFSET 0x00 +#define PWM_DUTY_REG_OFFSET 0x04 +#define PWM_PERIOD_REG_OFFSET 0x08 +#define PWM_BURST_REG_OFFSET 0x10 +#define PWM_SEQUENCE_REG_OFFSET 0x14 +#define PWM_DELAY_REG_OFFSET 0x18 + +/* CONTROL_REG */ +#define PWM_CONTROL_REG_ENABLE_POS 0 +#define PWM_CONTROL_REG_CBM_POS 1 +#define PWM_CONTROL_REG_PRESCALER_POS 2 +#define PWM_CONTROL_REG_DISABLE 0 +#define PWM_CONTROL_REG_ENABLE 1 +#define PWM_CONTROL_REG_CBM_ENABLE 1 + +#define PWM_BURST_REG_ONE_PULSE_PER_BURST 0 +#define PWM_SEQUENCE_REG_ONE_BURST_PER_SEQUENCE 0 +#define PWM_DELAY_REG_NO_DELAY 0 +#define PWM_PRESCALE 25 + +struct pwm_device { + struct list_head node; + struct platform_device *pdev; + + void __iomem *mmio_base; + + unsigned int pwm_id; + unsigned int use_count; +}; + +static DEFINE_MUTEX(pwm_lock); +static LIST_HEAD(pwm_list); +#if defined(CONFIG_DEBUG_FS) +static void init_debugfs(void); +#else +#define init_debugfs(x) +#endif + +/* + * PWM_CLK_RATE = 26000000 Hz + * + * period_ns = 10^9 * (PWM_PRESCALE + 1) * period / PWM_CLK_RATE + * duty_ns = 10^9 * (PWM_PRESCALE + 1) * dc / PWM_CLK_RATE + * + * period = period_ns * 26000000 / 10^9 / 26 => period = period_ns / 1000 + * dc = duty_ns * 26000000 / 10^9 / 26 => dc = duty_ns / 1000 + */ +#define MAGIC_DIVISOR (1000) +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +{ + u32 period; + u32 dc; + + dev_dbg(&pwm->pdev->dev, "%s duty_ns: %d period_ns: %d\n", + __func__, duty_ns, period_ns); + + if (pwm == NULL || period_ns == 0 || duty_ns >= period_ns) { + dev_err(&pwm->pdev->dev, "%s INVALID ARGUMENTS!\n", __func__); + return -EINVAL; + } + + period = period_ns / MAGIC_DIVISOR; + dc = duty_ns / MAGIC_DIVISOR; + + writel(period, pwm->mmio_base + PWM_PERIOD_REG_OFFSET); + writel(dc, pwm->mmio_base + PWM_DUTY_REG_OFFSET); + writel(PWM_BURST_REG_ONE_PULSE_PER_BURST, + pwm->mmio_base + PWM_BURST_REG_OFFSET); + writel(PWM_SEQUENCE_REG_ONE_BURST_PER_SEQUENCE, + pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET); + writel(PWM_DELAY_REG_NO_DELAY, pwm->mmio_base + PWM_DELAY_REG_OFFSET); + + return 0; +} +EXPORT_SYMBOL(pwm_config); + +int pwm_enable(struct pwm_device *pwm) +{ + u32 val; + + val = (PWM_CONTROL_REG_ENABLE << PWM_CONTROL_REG_ENABLE_POS); + val |= (PWM_CONTROL_REG_CBM_ENABLE << PWM_CONTROL_REG_CBM_POS); + val |= (PWM_PRESCALE << PWM_CONTROL_REG_PRESCALER_POS); + + writel(val, pwm->mmio_base + PWM_CONTROL_REG_OFFSET); + + return 0; +} +EXPORT_SYMBOL(pwm_enable); + +void pwm_disable(struct pwm_device *pwm) +{ + writel(PWM_CONTROL_REG_DISABLE, + pwm->mmio_base + PWM_CONTROL_REG_OFFSET); +} +EXPORT_SYMBOL(pwm_disable); + +struct pwm_device *pwm_request(int pwm_id, const char *label) +{ + struct pwm_device *pwm; + bool found = false; + + mutex_lock(&pwm_lock); + + list_for_each_entry(pwm, &pwm_list, node) { + if (pwm->pwm_id == pwm_id) { + found = true; + break; + } + } + + if (found) { + if (pwm->use_count == 0) + pwm->use_count++; + else + pwm = ERR_PTR(-EBUSY); + } else { + pwm = ERR_PTR(-ENOENT); + } + + mutex_unlock(&pwm_lock); + return pwm; +} +EXPORT_SYMBOL(pwm_request); + +void pwm_free(struct pwm_device *pwm) +{ + mutex_lock(&pwm_lock); + + if (pwm->use_count) + pwm->use_count--; + else + dev_warn(&pwm->pdev->dev, "PWM device already freed\n"); + + mutex_unlock(&pwm_lock); +} +EXPORT_SYMBOL(pwm_free); + +int __init pwm_probe(struct platform_device *pdev) +{ + struct pwm_device *pwm; + struct resource *r; + int ret = 0; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); + if (pwm == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + pwm->pwm_id = pdev->id; + pwm->pdev = pdev; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + dev_err(&pdev->dev, "no memory resource defined\n"); + ret = -ENODEV; + goto err_free; + } + + pwm->mmio_base = ioremap(r->start, resource_size(r)); + if (pwm->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to ioremap() registers\n"); + ret = -ENODEV; + goto err_free; + } + + mutex_lock(&pwm_lock); + list_add_tail(&pwm->node, &pwm_list); + mutex_unlock(&pwm_lock); + + platform_set_drvdata(pdev, pwm); + + init_debugfs(); + + return 0; + +err_free: + kfree(pwm); + return ret; +} + +static int __devexit pwm_remove(struct platform_device *pdev) +{ + struct pwm_device *pwm; + + pwm = platform_get_drvdata(pdev); + if (pwm == NULL) + return -ENODEV; + + mutex_lock(&pwm_lock); + list_del(&pwm->node); + mutex_unlock(&pwm_lock); + + iounmap(pwm->mmio_base); + + kfree(pwm); + return 0; +} + +static struct platform_driver pwm_driver = { + .driver = { + .name = "pwm", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(pwm_remove), +}; + +static int __init pwm_init(void) +{ + int ret = 0; + + ret = platform_driver_probe(&pwm_driver, pwm_probe); + if (ret) { + pr_err("PWM: probe failed ret=%d\n", ret); + return ret; + } + + return ret; +} + +#if defined(CONFIG_DEBUG_FS) +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static int pwm_dump(struct seq_file *s, void *data) +{ + struct list_head *pos; + struct pwm_device *pwm; + int pwm_index = 0; + + mutex_lock(&pwm_lock); + + list_for_each(pos, &pwm_list) { + pwm = (struct pwm_device *) + list_entry(pos, struct pwm_device, node); + + seq_printf(s, "===========================\n" + " PWM DUMP %d\n" + " mmio_base: 0x%p\n" + " CONTROL : 0x%X\n" + " DUTY : 0x%X\n" + " PERIOD : 0x%X\n" + " BURST : 0x%X\n" + " SEQUENCE : 0x%X\n" + " DELAY : 0x%X\n", + pwm_index, + pwm->mmio_base, + readl(pwm->mmio_base + PWM_CONTROL_REG_OFFSET), + readl(pwm->mmio_base + PWM_DUTY_REG_OFFSET), + readl(pwm->mmio_base + PWM_PERIOD_REG_OFFSET), + readl(pwm->mmio_base + PWM_BURST_REG_OFFSET), + readl(pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET), + readl(pwm->mmio_base + PWM_DELAY_REG_OFFSET)); + pwm_index++; + } + + mutex_unlock(&pwm_lock); + + return 0; +} + +static int pwm_open(struct inode *inode, struct file *file) +{ + return single_open(file, pwm_dump, NULL); +} + +static int get_value(char **c, char *s, int *v) +{ + char *val; + long value; + int ret = -1; + + if (c != NULL) { + val = strsep(c, s); + + if (val) { + ret = strict_strtol(val, 10, &value); + + if (!ret) + *v = value; + } + } + + return ret; +} + +#define MAX_BUFFER_SIZE 64 + +static int pwm_write_raw(struct file *file, const char __user *buffer, + size_t size, loff_t *offset) +{ + char int_buf[MAX_BUFFER_SIZE]; + char *token; + u32 period; + u32 dc; + u32 burst; + u32 seq; + u32 delay; + u32 ctrl; + int max_size = max(size, strlen(buffer)); + + struct pwm_device *pwm = (struct pwm_device *) + list_first_entry(&pwm_list, struct pwm_device, node); + + /* Copy the buffer since strsep alters it */ + strncpy((char *) &int_buf, (char*)buffer, max_size); + + token = (char *) &int_buf; + + if (get_value(&token, " ", &period)) { + dev_err(&pwm->pdev->dev, "%s 1\n", __func__); + return size; + } + + if (get_value(&token, " ", &dc)) { + dev_err(&pwm->pdev->dev, "%s 2\n", __func__); + return size; + } + + if (get_value(&token, " ", &burst)) { + dev_err(&pwm->pdev->dev, "%s 3\n", __func__); + return size; + } + + if (get_value(&token, " ", &seq)) { + dev_err(&pwm->pdev->dev, "%s 4\n", __func__); + return size; + } + + if (get_value(&token, " ", &delay)) { + dev_err(&pwm->pdev->dev, "%s 5\n", __func__); + return size; + } + + if (get_value(&token, "\n", &ctrl)) { + dev_err(&pwm->pdev->dev, "%s 6\n", __func__); + return size; + } + + dev_dbg(&pwm->pdev->dev, + "%s p: 0x%X d: 0x%X b: 0x%X s: 0x%X d: 0x%X c: 0x%X\n" + , __func__, period, dc, burst, seq, delay, ctrl); + + writel(period, pwm->mmio_base + PWM_PERIOD_REG_OFFSET); + writel(dc , pwm->mmio_base + PWM_DUTY_REG_OFFSET); + writel(burst , pwm->mmio_base + PWM_BURST_REG_OFFSET); + writel(seq , pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET); + writel(delay , pwm->mmio_base + PWM_DELAY_REG_OFFSET); + writel(ctrl , pwm->mmio_base + PWM_CONTROL_REG_OFFSET); + + return size; +} + +static int pwm_write(struct file *file, + const char __user *buffer, + size_t size, loff_t *offset) +{ + char int_buf[MAX_BUFFER_SIZE]; + char *token; + u32 period = 0; + u32 dc = 0; + u32 ctrl = 0; + int max_size = max(size, strlen(buffer)); + + struct pwm_device *pwm = (struct pwm_device *) + list_first_entry(&pwm_list, struct pwm_device, node); + + /* Copy the buffer since strsep alters it */ + strncpy((char *) &int_buf, (char*)buffer, max((int) size, max_size)); + + token = (char *) &int_buf; + + if (get_value(&token, " ", &period)) { + dev_err(&pwm->pdev->dev, "%s 1\n", __func__); + return size; + } + + if (get_value(&token, " ", &dc)) { + dev_err(&pwm->pdev->dev, "%s 2\n", __func__); + return size; + } + + if (get_value(&token, "\n", &ctrl)) { + dev_err(&pwm->pdev->dev, "%s 3\n", __func__); + return size; + } + + dev_dbg(&pwm->pdev->dev, "%s p: 0x%X d: 0x%X c: 0x%X\n", + __func__, period, dc, ctrl); + + if (ctrl == 0) + pwm_disable(pwm); + else { + pwm_config(pwm, dc, period); + pwm_enable(pwm); + } + + return size; +} + +static const struct file_operations pwm_operations = { + .owner = THIS_MODULE, + .open = pwm_open, + .read = seq_read, + .write = pwm_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations pwm_operations_raw = { + .owner = THIS_MODULE, + .open = pwm_open, + .read = seq_read, + .write = pwm_write_raw, + .llseek = seq_lseek, + .release = single_release, +}; + +static void init_debugfs(void) +{ + (void) debugfs_create_file("pwm_if", S_IFREG | S_IRUGO | S_IWUGO, + NULL, NULL, &pwm_operations); + (void) debugfs_create_file("pwm_raw", S_IFREG | S_IRUGO | S_IWUGO, + NULL, NULL, &pwm_operations_raw); +} +#endif + +module_init(pwm_init); + +static void __exit pwm_exit(void) +{ + platform_driver_unregister(&pwm_driver); +} +module_exit(pwm_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-ux500/reboot_reasons.c b/arch/arm/mach-ux500/reboot_reasons.c new file mode 100644 index 00000000000..b625c6a615f --- /dev/null +++ b/arch/arm/mach-ux500/reboot_reasons.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Rickard Evertsson <rickard.evertsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL) version 2 + * + * Use this file to customize your reboot / sw reset reasons. Add, remove or + * modify reasons in reboot_reasons[]. + */ + +#include <linux/kernel.h> +#include <mach/reboot_reasons.h> + +struct reboot_reason reboot_reasons[] = { + {"crash", SW_RESET_CRASH}, + {"", SW_RESET_NORMAL}, /* Normal Boot */ +}; + +unsigned int reboot_reasons_size = ARRAY_SIZE(reboot_reasons); diff --git a/arch/arm/mach-ux500/regulator-u5500.c b/arch/arm/mach-ux500/regulator-u5500.c new file mode 100644 index 00000000000..bd988c7c109 --- /dev/null +++ b/arch/arm/mach-ux500/regulator-u5500.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <mach/prcmu-fw-api.h> + +#include "regulator-ux500.h" +#include "regulator-u5500.h" + +static struct u8500_regulator_info +u5500_regulator_info[U5500_NUM_REGULATORS] = { + [U5500_REGULATOR_VAPE] = { + .desc = { + .name = "u5500-vape", + .id = U5500_REGULATOR_VAPE, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, +}; + +static int __devinit u5500_regulator_probe(struct platform_device *pdev) +{ + return ux500_regulator_probe(pdev, u5500_regulator_info, + ARRAY_SIZE(u5500_regulator_info)); +} + +static int __devexit u5500_regulator_remove(struct platform_device *pdev) +{ + return ux500_regulator_remove(pdev, u5500_regulator_info, + ARRAY_SIZE(u5500_regulator_info)); +} + +static struct platform_driver u5500_regulator_driver = { + .driver = { + .name = "u5500-regulators", + .owner = THIS_MODULE, + }, + .probe = u5500_regulator_probe, + .remove = __devexit_p(u5500_regulator_remove), +}; + +static int __init u5500_regulator_init(void) +{ + return platform_driver_register(&u5500_regulator_driver); +} + +static void __exit u5500_regulator_exit(void) +{ + platform_driver_unregister(&u5500_regulator_driver); +} + +arch_initcall(u5500_regulator_init); +module_exit(u5500_regulator_exit); + +MODULE_DESCRIPTION("U5500 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-ux500/regulator-u5500.h b/arch/arm/mach-ux500/regulator-u5500.h new file mode 100644 index 00000000000..2c363096d12 --- /dev/null +++ b/arch/arm/mach-ux500/regulator-u5500.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ + +#ifndef __REGULATOR_U5500_H +#define __REGULATOR_U5500_H + +enum u5500_regulator_id { + U5500_REGULATOR_VAPE, + U5500_NUM_REGULATORS +}; + +#endif diff --git a/arch/arm/mach-ux500/regulator-u8500.c b/arch/arm/mach-ux500/regulator-u8500.c new file mode 100644 index 00000000000..fbbff443ba6 --- /dev/null +++ b/arch/arm/mach-ux500/regulator-u8500.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <mach/prcmu-fw-api.h> + +#include "regulator-ux500.h" +#include "regulator-u8500.h" + +static struct u8500_regulator_info + u8500_regulator_info[U8500_NUM_REGULATORS] = { + [U8500_REGULATOR_VAPE] = { + .desc = { + .name = "u8500-vape", + .id = U8500_REGULATOR_VAPE, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VARM] = { + .desc = { + .name = "u8500-varm", + .id = U8500_REGULATOR_VARM, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VMODEM] = { + .desc = { + .name = "u8500-vmodem", + .id = U8500_REGULATOR_VMODEM, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VPLL] = { + .desc = { + .name = "u8500-vpll", + .id = U8500_REGULATOR_VPLL, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VSMPS1] = { + .desc = { + .name = "u8500-vsmps1", + .id = U8500_REGULATOR_VSMPS1, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VSMPS2] = { + .desc = { + .name = "u8500-vsmps2", + .id = U8500_REGULATOR_VSMPS2, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .exclude_from_power_state = true, + }, + [U8500_REGULATOR_VSMPS3] = { + .desc = { + .name = "u8500-vsmps3", + .id = U8500_REGULATOR_VSMPS3, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_VRF1] = { + .desc = { + .name = "u8500-vrf1", + .id = U8500_REGULATOR_VRF1, + .ops = &ux500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + [U8500_REGULATOR_SWITCH_SVAMMDSP] = { + .desc = { + .name = "u8500-sva-mmdsp", + .id = U8500_REGULATOR_SWITCH_SVAMMDSP, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SVAMMDSP, + }, + [U8500_REGULATOR_SWITCH_SVAMMDSPRET] = { + .desc = { + .name = "u8500-sva-mmdsp-ret", + .id = U8500_REGULATOR_SWITCH_SVAMMDSPRET, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SVAMMDSP, + .is_ramret = true, + }, + [U8500_REGULATOR_SWITCH_SVAPIPE] = { + .desc = { + .name = "u8500-sva-pipe", + .id = U8500_REGULATOR_SWITCH_SVAPIPE, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SVAPIPE, + }, + [U8500_REGULATOR_SWITCH_SIAMMDSP] = { + .desc = { + .name = "u8500-sia-mmdsp", + .id = U8500_REGULATOR_SWITCH_SIAMMDSP, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SIAMMDSP, + }, + [U8500_REGULATOR_SWITCH_SIAMMDSPRET] = { + .desc = { + .name = "u8500-sia-mmdsp-ret", + .id = U8500_REGULATOR_SWITCH_SIAMMDSPRET, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SIAMMDSP, + .is_ramret = true, + }, + [U8500_REGULATOR_SWITCH_SIAPIPE] = { + .desc = { + .name = "u8500-sia-pipe", + .id = U8500_REGULATOR_SWITCH_SIAPIPE, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SIAPIPE, + }, + [U8500_REGULATOR_SWITCH_SGA] = { + .desc = { + .name = "u8500-sga", + .id = U8500_REGULATOR_SWITCH_SGA, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_SGA, + }, + [U8500_REGULATOR_SWITCH_B2R2_MCDE] = { + .desc = { + .name = "u8500-b2r2-mcde", + .id = U8500_REGULATOR_SWITCH_B2R2_MCDE, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_B2R2_MCDE, + }, + [U8500_REGULATOR_SWITCH_ESRAM12] = { + .desc = { + .name = "u8500-esram12", + .id = U8500_REGULATOR_SWITCH_ESRAM12, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_ESRAM12, + .is_enabled = true, + }, + [U8500_REGULATOR_SWITCH_ESRAM12RET] = { + .desc = { + .name = "u8500-esram12-ret", + .id = U8500_REGULATOR_SWITCH_ESRAM12RET, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_ESRAM12, + .is_ramret = true, + }, + [U8500_REGULATOR_SWITCH_ESRAM34] = { + .desc = { + .name = "u8500-esram34", + .id = U8500_REGULATOR_SWITCH_ESRAM34, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_ESRAM34, + .is_enabled = true, + }, + [U8500_REGULATOR_SWITCH_ESRAM34RET] = { + .desc = { + .name = "u8500-esram34-ret", + .id = U8500_REGULATOR_SWITCH_ESRAM34RET, + .ops = &ux500_regulator_switch_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .epod_id = EPOD_ID_ESRAM34, + .is_ramret = true, + }, +}; + +static int __devinit u8500_regulator_probe(struct platform_device *pdev) +{ + int ret; + + ret = ux500_regulator_probe(pdev, u8500_regulator_info, + ARRAY_SIZE(u8500_regulator_info)); + if (!ret) + regulator_has_full_constraints(); + + return ret; +} + +static int __devexit u8500_regulator_remove(struct platform_device *pdev) +{ + return ux500_regulator_remove(pdev, u8500_regulator_info, + ARRAY_SIZE(u8500_regulator_info)); +} + +static struct platform_driver u8500_regulator_driver = { + .driver = { + .name = "u8500-regulators", + .owner = THIS_MODULE, + }, + .probe = u8500_regulator_probe, + .remove = __devexit_p(u8500_regulator_remove), +}; + +static int __init u8500_regulator_init(void) +{ + return platform_driver_register(&u8500_regulator_driver); +} + +static void __exit u8500_regulator_exit(void) +{ + platform_driver_unregister(&u8500_regulator_driver); +} + +/* replaced subsys_initcall as regulators must be turned on early */ +arch_initcall(u8500_regulator_init); +module_exit(u8500_regulator_exit); + +MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); +MODULE_DESCRIPTION("U8500 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-ux500/regulator-u8500.h b/arch/arm/mach-ux500/regulator-u8500.h new file mode 100644 index 00000000000..01dfeeb9da7 --- /dev/null +++ b/arch/arm/mach-ux500/regulator-u8500.h @@ -0,0 +1,46 @@ +/* + * 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 platform specific regulators on U8500 + */ + +#ifndef __REGULATOR_H__ +#define __REGULATOR_H__ + +/* Number of U8500 regulators and regulator enumeration */ +enum u8500_regulator_id { + U8500_REGULATOR_VAPE, + U8500_REGULATOR_VARM, + U8500_REGULATOR_VMODEM, + U8500_REGULATOR_VPLL, + U8500_REGULATOR_VSMPS1, + U8500_REGULATOR_VSMPS2, + U8500_REGULATOR_VSMPS3, + U8500_REGULATOR_VRF1, + U8500_REGULATOR_SWITCH_SVAMMDSP, + U8500_REGULATOR_SWITCH_SVAMMDSPRET, + U8500_REGULATOR_SWITCH_SVAPIPE, + U8500_REGULATOR_SWITCH_SIAMMDSP, + U8500_REGULATOR_SWITCH_SIAMMDSPRET, + U8500_REGULATOR_SWITCH_SIAPIPE, + U8500_REGULATOR_SWITCH_SGA, + U8500_REGULATOR_SWITCH_B2R2_MCDE, + U8500_REGULATOR_SWITCH_ESRAM12, + U8500_REGULATOR_SWITCH_ESRAM12RET, + U8500_REGULATOR_SWITCH_ESRAM34, + U8500_REGULATOR_SWITCH_ESRAM34RET, + U8500_NUM_REGULATORS +}; + +/* + * Exported interface for CPUIdle only. This function is called with all + * interrupts turned off. + */ +int power_state_active_is_enabled(void); + +#endif + diff --git a/arch/arm/mach-ux500/regulator-ux500.c b/arch/arm/mach-ux500/regulator-ux500.c new file mode 100644 index 00000000000..fc6568a6e5a --- /dev/null +++ b/arch/arm/mach-ux500/regulator-ux500.c @@ -0,0 +1,392 @@ +/* + * 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 + * + * Platform specific regulators on U8500 + * + * NOTE! The power domains in here will be updated once B2R2 and MCDE are + * converted to use the regulator API. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include "regulator-ux500.h" + +#include <mach/prcmu-fw-api.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 ux500_regulator { + char *name; + void (*enable)(void); + int (*disable)(void); +}; + +/* + * Don't add any clients to this struct without checking with regulator + * responsible! + */ +static struct ux500_regulator ux500_atomic_regulators[] = { + { + .name = "dma40.0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "ssp0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "ssp1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi2", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi3", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, +}; + +struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ux500_atomic_regulators); i++) { + if (!strcmp(dev_name(dev), ux500_atomic_regulators[i].name)) + return &ux500_atomic_regulators[i]; + } + + return ERR_PTR(-EINVAL); +} + +int ux500_regulator_atomic_enable(struct ux500_regulator *regulator) +{ + if (regulator) { + regulator->enable(); + return 0; + } + return -EINVAL; +} + +int ux500_regulator_atomic_disable(struct ux500_regulator *regulator) +{ + if (regulator) + return regulator->disable(); + else + return -EINVAL; +} + +void ux500_regulator_put(struct ux500_regulator *regulator) +{ + /* Here for symetric reasons and for possible future use */ +} + +static int u8500_regulator_enable(struct regulator_dev *rdev) +{ + struct u8500_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 = 1; + if (!info->exclude_from_power_state) + power_state_active_enable(); + + return 0; +} + +static int u8500_regulator_disable(struct regulator_dev *rdev) +{ + struct u8500_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 = 0; + if (!info->exclude_from_power_state) + ret = power_state_active_disable(); + + return ret; +} + +static int u8500_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct u8500_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; +} + +/* u8500 regulator operations */ +struct regulator_ops ux500_regulator_ops = { + .enable = u8500_regulator_enable, + .disable = u8500_regulator_disable, + .is_enabled = u8500_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 u8500_regulator_switch_enable(struct regulator_dev *rdev) +{ + struct u8500_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 = 1; +out: + return ret; +} + +static int u8500_regulator_switch_disable(struct regulator_dev *rdev) +{ + struct u8500_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 u8500_regulator_switch_is_enabled(struct regulator_dev *rdev) +{ + struct u8500_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; +} + +struct regulator_ops ux500_regulator_switch_ops = { + .enable = u8500_regulator_switch_enable, + .disable = u8500_regulator_switch_disable, + .is_enabled = u8500_regulator_switch_is_enabled, +}; + +int __devinit +ux500_regulator_probe(struct platform_device *pdev, + struct u8500_regulator_info *regulator_info, + int num_regulators) +{ + struct regulator_init_data **u8500_init_data = + dev_get_platdata(&pdev->dev); + int i, err; + + /* register all regulators */ + for (i = 0; i < num_regulators; i++) { + struct u8500_regulator_info *info; + struct regulator_init_data *init_data = u8500_init_data[i]; + + /* assign per-regulator data */ + info = ®ulator_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 = ®ulator_info[i]; + regulator_unregister(info->rdev); + i--; + } + return err; + } + + dev_vdbg(rdev_get_dev(info->rdev), + "regulator-%s-probed\n", info->desc.name); + } + + return 0; +} + +int __devexit +ux500_regulator_remove(struct platform_device *pdev, + struct u8500_regulator_info *regulator_info, + int num_regulators) +{ + int i; + + for (i = 0; i < num_regulators; i++) { + struct u8500_regulator_info *info; + + info = ®ulator_info[i]; + + dev_vdbg(rdev_get_dev(info->rdev), + "regulator-%s-remove\n", info->desc.name); + + regulator_unregister(info->rdev); + } + + return 0; +} diff --git a/arch/arm/mach-ux500/regulator-ux500.h b/arch/arm/mach-ux500/regulator-ux500.h new file mode 100644 index 00000000000..b62863881b1 --- /dev/null +++ b/arch/arm/mach-ux500/regulator-ux500.h @@ -0,0 +1,39 @@ +#ifndef __REGULATOR_UX500_H +#define __REGULATOR_UX500_H + +struct platform_device; + +/** + * struct u8500_regulator_info - u8500 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) + * @exclude_from_power_state: don't let this regulator prevent ApSLeep + */ +struct u8500_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; +}; + +extern struct regulator_ops ux500_regulator_ops; +extern struct regulator_ops ux500_regulator_switch_ops; + +int ux500_regulator_probe(struct platform_device *pdev, + struct u8500_regulator_info *info, + int num_regulators); + +int ux500_regulator_remove(struct platform_device *pdev, + struct u8500_regulator_info *info, + int num_regulators); + +#endif diff --git a/arch/arm/mach-ux500/sensors1p.c b/arch/arm/mach-ux500/sensors1p.c new file mode 100644 index 00000000000..e7f4642b1d9 --- /dev/null +++ b/arch/arm/mach-ux500/sensors1p.c @@ -0,0 +1,298 @@ + +/* + * Copyright (C) 2009-2010 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * Simple userspace interface for + * Proximity Sensor Osram SFH 7741 and HAL switch Samsung HED54XXU11 + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + * + * This driver is only there for making Android happy. It is not ment + * for mainline. + */ + + +#include <linux/platform_device.h> +#include <linux/sysfs.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> + +#include <mach/sensors1p.h> + +struct sensor { + struct regulator *regulator; + int pin; + int startup_time; + int active; + u64 when_enabled; +}; + +struct sensors1p { + struct sensor hal; + struct sensor proximity; +}; + +static int sensors1p_power_write(struct device *dev, + struct sensor *s, const char *buf) +{ + int val; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + if (val != s->active) { + if (val) { + regulator_enable(s->regulator); + s->when_enabled = get_jiffies_64() + + msecs_to_jiffies(s->startup_time); + } else + regulator_disable(s->regulator); + } + s->active = val; + + return strnlen(buf, PAGE_SIZE); + +} + +static ssize_t sensors1p_sysfs_hal_active_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sensors1p_power_write(dev, &s->hal, buf); + +} + +static ssize_t sensors1p_sysfs_proximity_active_set(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + + + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sensors1p_power_write(dev, &s->proximity, buf); + +} + +static ssize_t sensors1p_sysfs_hal_active_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sprintf(buf, "%d", s->hal.active); +} + +static ssize_t sensors1p_sysfs_proximity_active_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sprintf(buf, "%d", s->proximity.active); +} + +static int sensors1p_read(struct device *dev, struct sensor *s, char *buf) +{ + int ret; + + if (!s->active) + return -EINVAL; + + /* Only wait if read() is called before the sensor is up and running + * Since jiffies wraps, always sleep maximum time. + */ + if (time_before64(get_jiffies_64(), s->when_enabled)) + mdelay(s->startup_time); + + /* For some odd reason, setting direction in the probe function fails */ + ret = gpio_direction_input(s->pin); + + if (ret) + dev_err(dev, "Failed to set GPIO pin %d to input.\n", s->pin); + else + ret = gpio_get_value(s->pin); + + return sprintf(buf, "%d", ret); +} + +static ssize_t sensors1p_sysfs_hal_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sensors1p_read(dev, &s->hal, buf); +} + +static ssize_t sensors1p_sysfs_proximity_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensors1p *s = platform_get_drvdata(container_of(dev, + struct platform_device, + dev)); + return sensors1p_read(dev, &s->proximity, buf); +} + +static DEVICE_ATTR(proximity_activate, 0666, + sensors1p_sysfs_proximity_active_get, + sensors1p_sysfs_proximity_active_set); +static DEVICE_ATTR(hal_activate, 0666, + sensors1p_sysfs_hal_active_get, + sensors1p_sysfs_hal_active_set); +static DEVICE_ATTR(proximity, 0444, sensors1p_sysfs_proximity_show, NULL); +static DEVICE_ATTR(hal, 0444, sensors1p_sysfs_hal_show, NULL); + +static struct attribute *sensors1p_attrs[] = { + &dev_attr_proximity_activate.attr, + &dev_attr_hal_activate.attr, + &dev_attr_proximity.attr, + &dev_attr_hal.attr, + NULL, +}; + +static struct attribute_group sensors1p_attr_group = { + .name = NULL, + .attrs = sensors1p_attrs, +}; + +static int __init sensors1p_probe(struct platform_device *pdev) +{ + int err = -EINVAL; + struct sensors1p_config *c; + struct sensors1p *s = NULL; + + if (!pdev) + goto out; + + c = pdev->dev.platform_data; + + if (c == NULL) { + dev_err(&pdev->dev, "Error: Missconfigured.\n"); + goto out; + } + + s = kzalloc(sizeof(struct sensors1p), GFP_KERNEL); + + if (s == NULL) { + dev_err(&pdev->dev, + "Could not allocate struct memory!\n"); + err = -ENOMEM; + goto out; + } + + s->hal.pin = c->hal.pin; + err = gpio_request(c->hal.pin, "hal sensor"); + if (err < 0) { + dev_err(&pdev->dev, "gpio_request failed with err: %d", err); + goto err_hal_gpio; + } + + s->proximity.pin = c->proximity.pin; + err = gpio_request(c->proximity.pin, "proximity sensor"); + if (err < 0) { + dev_err(&pdev->dev, "gpio_request failed with err: %d", err); + goto err_proximity_gpio; + } + + s->hal.startup_time = c->hal.startup_time; + s->proximity.startup_time = c->proximity.startup_time; + + + s->hal.regulator = regulator_get(&pdev->dev, c->hal.regulator); + + if (IS_ERR(s->hal.regulator)) { + dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n", + c->hal.regulator); + err = PTR_ERR(s->hal.regulator); + goto err_hal_reg; + } + s->proximity.regulator = regulator_get(&pdev->dev, + c->proximity.regulator); + + if (IS_ERR(s->proximity.regulator)) { + dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n", + c->proximity.regulator); + err = PTR_ERR(s->proximity.regulator); + goto err_proximity_reg; + } + + err = sysfs_create_group(&pdev->dev.kobj, &sensors1p_attr_group); + + if (err) { + dev_err(&pdev->dev, "Failed to create sysfs entries.\n"); + goto err_sysfs; + } + + platform_set_drvdata(pdev, s); + + return 0; + +err_sysfs: + regulator_put(s->proximity.regulator); +err_proximity_reg: + regulator_put(s->hal.regulator); +err_hal_reg: + gpio_free(s->proximity.pin); +err_proximity_gpio: + gpio_free(s->hal.pin); +err_hal_gpio: + kfree(s); +out: + return err; +} + +static int __exit sensors1p_remove(struct platform_device *pdev) +{ + struct sensors1p *s = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &sensors1p_attr_group); + gpio_free(s->hal.pin); + gpio_free(s->proximity.pin); + regulator_put(s->hal.regulator); + regulator_put(s->proximity.regulator); + kfree(s); + return 0; +} + +static struct platform_driver sensors1p_driver = { + .remove = __exit_p(sensors1p_remove), + .driver = { + .name = "sensors1p", + .owner = THIS_MODULE, + }, +}; + +static int __init sensors1p_init(void) +{ + return platform_driver_probe(&sensors1p_driver, sensors1p_probe); +} + +static void __exit sensors1p_exit(void) +{ + platform_driver_unregister(&sensors1p_driver); +} + +late_initcall(sensors1p_init); +module_exit(sensors1p_exit); + +MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>"); +MODULE_DESCRIPTION("One pin gpio sensors driver (Proximity+HAL)"); +MODULE_LICENSE("GPLv2"); diff --git a/arch/arm/mach-ux500/ste-dma40-db8500.h b/arch/arm/mach-ux500/ste-dma40-db8500.h deleted file mode 100644 index e7016278dfa..00000000000 --- a/arch/arm/mach-ux500/ste-dma40-db8500.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * arch/arm/mach-ux500/ste_dma40_db8500.h - * DB8500-SoC-specific configuration for DMA40 - * - * Copyright (C) ST-Ericsson 2007-2010 - * License terms: GNU General Public License (GPL) version 2 - * Author: Per Friden <per.friden@stericsson.com> - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> - */ -#ifndef STE_DMA40_DB8500_H -#define STE_DMA40_DB8500_H - -#define STEDMA40_NR_DEV 64 - -enum dma_src_dev_type { - STEDMA40_DEV_SPI0_RX = 0, - STEDMA40_DEV_SD_MMC0_RX = 1, - STEDMA40_DEV_SD_MMC1_RX = 2, - STEDMA40_DEV_SD_MMC2_RX = 3, - STEDMA40_DEV_I2C1_RX = 4, - STEDMA40_DEV_I2C3_RX = 5, - STEDMA40_DEV_I2C2_RX = 6, - STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */ - STEDMA40_DEV_SSP0_RX = 8, - STEDMA40_DEV_SSP1_RX = 9, - STEDMA40_DEV_MCDE_RX = 10, - STEDMA40_DEV_UART2_RX = 11, - STEDMA40_DEV_UART1_RX = 12, - STEDMA40_DEV_UART0_RX = 13, - STEDMA40_DEV_MSP2_RX = 14, - STEDMA40_DEV_I2C0_RX = 15, - STEDMA40_DEV_USB_OTG_IEP_8 = 16, - STEDMA40_DEV_USB_OTG_IEP_1_9 = 17, - STEDMA40_DEV_USB_OTG_IEP_2_10 = 18, - STEDMA40_DEV_USB_OTG_IEP_3_11 = 19, - STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20, - STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21, - STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22, - STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23, - STEDMA40_DEV_SRC_SXA0_RX_TX = 24, - STEDMA40_DEV_SRC_SXA1_RX_TX = 25, - STEDMA40_DEV_SRC_SXA2_RX_TX = 26, - STEDMA40_DEV_SRC_SXA3_RX_TX = 27, - STEDMA40_DEV_SD_MM2_RX = 28, - STEDMA40_DEV_SD_MM0_RX = 29, - STEDMA40_DEV_MSP1_RX = 30, - /* - * This channel is either SlimBus or MSP, - * never both at the same time. - */ - STEDMA40_SLIM0_CH0_RX = 31, - STEDMA40_DEV_MSP0_RX = 31, - STEDMA40_DEV_SD_MM1_RX = 32, - STEDMA40_DEV_SPI2_RX = 33, - STEDMA40_DEV_I2C3_RX2 = 34, - STEDMA40_DEV_SPI1_RX = 35, - STEDMA40_DEV_USB_OTG_IEP_4_12 = 36, - STEDMA40_DEV_USB_OTG_IEP_5_13 = 37, - STEDMA40_DEV_USB_OTG_IEP_6_14 = 38, - STEDMA40_DEV_USB_OTG_IEP_7_15 = 39, - STEDMA40_DEV_SPI3_RX = 40, - STEDMA40_DEV_SD_MM3_RX = 41, - STEDMA40_DEV_SD_MM4_RX = 42, - STEDMA40_DEV_SD_MM5_RX = 43, - STEDMA40_DEV_SRC_SXA4_RX_TX = 44, - STEDMA40_DEV_SRC_SXA5_RX_TX = 45, - STEDMA40_DEV_SRC_SXA6_RX_TX = 46, - STEDMA40_DEV_SRC_SXA7_RX_TX = 47, - STEDMA40_DEV_CAC1_RX = 48, - /* RX channels 49 and 50 are unused */ - STEDMA40_DEV_MSHC_RX = 51, - STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52, - STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53, - STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54, - STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55, - /* RX channels 56 thru 60 are unused */ - STEDMA40_DEV_CAC0_RX = 61, - /* RX channels 62 and 63 are unused */ -}; - -enum dma_dest_dev_type { - STEDMA40_DEV_SPI0_TX = 0, - STEDMA40_DEV_SD_MMC0_TX = 1, - STEDMA40_DEV_SD_MMC1_TX = 2, - STEDMA40_DEV_SD_MMC2_TX = 3, - STEDMA40_DEV_I2C1_TX = 4, - STEDMA40_DEV_I2C3_TX = 5, - STEDMA40_DEV_I2C2_TX = 6, - STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */ - STEDMA40_DEV_SSP0_TX = 8, - STEDMA40_DEV_SSP1_TX = 9, - /* TX channel 10 is unused */ - STEDMA40_DEV_UART2_TX = 11, - STEDMA40_DEV_UART1_TX = 12, - STEDMA40_DEV_UART0_TX= 13, - STEDMA40_DEV_MSP2_TX = 14, - STEDMA40_DEV_I2C0_TX = 15, - STEDMA40_DEV_USB_OTG_OEP_8 = 16, - STEDMA40_DEV_USB_OTG_OEP_1_9 = 17, - STEDMA40_DEV_USB_OTG_OEP_2_10= 18, - STEDMA40_DEV_USB_OTG_OEP_3_11 = 19, - STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20, - STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21, - STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22, - STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23, - STEDMA40_DEV_DST_SXA0_RX_TX = 24, - STEDMA40_DEV_DST_SXA1_RX_TX = 25, - STEDMA40_DEV_DST_SXA2_RX_TX = 26, - STEDMA40_DEV_DST_SXA3_RX_TX = 27, - STEDMA40_DEV_SD_MM2_TX = 28, - STEDMA40_DEV_SD_MM0_TX = 29, - STEDMA40_DEV_MSP1_TX = 30, - /* - * This channel is either SlimBus or MSP, - * never both at the same time. - */ - STEDMA40_SLIM0_CH0_TX = 31, - STEDMA40_DEV_MSP0_TX = 31, - STEDMA40_DEV_SD_MM1_TX = 32, - STEDMA40_DEV_SPI2_TX = 33, - /* Secondary I2C3 channel */ - STEDMA40_DEV_I2C3_TX2 = 34, - STEDMA40_DEV_SPI1_TX = 35, - STEDMA40_DEV_USB_OTG_OEP_4_12 = 36, - STEDMA40_DEV_USB_OTG_OEP_5_13 = 37, - STEDMA40_DEV_USB_OTG_OEP_6_14 = 38, - STEDMA40_DEV_USB_OTG_OEP_7_15 = 39, - STEDMA40_DEV_SPI3_TX = 40, - STEDMA40_DEV_SD_MM3_TX = 41, - STEDMA40_DEV_SD_MM4_TX = 42, - STEDMA40_DEV_SD_MM5_TX = 43, - STEDMA40_DEV_DST_SXA4_RX_TX = 44, - STEDMA40_DEV_DST_SXA5_RX_TX = 45, - STEDMA40_DEV_DST_SXA6_RX_TX = 46, - STEDMA40_DEV_DST_SXA7_RX_TX = 47, - STEDMA40_DEV_CAC1_TX = 48, - STEDMA40_DEV_CAC1_TX_HAC1_TX = 49, - STEDMA40_DEV_HAC1_TX = 50, - STEDMA40_MEMXCPY_TX_0 = 51, - STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52, - STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53, - STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54, - STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55, - STEDMA40_MEMCPY_TX_1 = 56, - STEDMA40_MEMCPY_TX_2 = 57, - STEDMA40_MEMCPY_TX_3 = 58, - STEDMA40_MEMCPY_TX_4 = 59, - STEDMA40_MEMCPY_TX_5 = 60, - STEDMA40_DEV_CAC0_TX = 61, - STEDMA40_DEV_CAC0_TX_HAC0_TX = 62, - STEDMA40_DEV_HAC0_TX = 63, -}; - -#endif diff --git a/arch/arm/mach-ux500/tee_service_svp.c b/arch/arm/mach-ux500/tee_service_svp.c new file mode 100644 index 00000000000..8c68e51ab74 --- /dev/null +++ b/arch/arm/mach-ux500/tee_service_svp.c @@ -0,0 +1,66 @@ +/* + * TEE service to handle the calls to trusted applications in SVP. + * + * Copyright (C) ST-Ericsson SA 2010 + * Author: Shujuan Chen <shujuan.chen@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/tee.h> +#include <linux/err.h> +#include "mach/tee_ta_start_modem.h" + +static int cmp_uuid_start_modem(struct tee_uuid *uuid) +{ + int ret = -EINVAL; + + if (uuid == NULL) + return -EINVAL; + + /* This handles the calls to TA for start the modem */ + if ((uuid->timeLow == UUID_TEE_TA_START_MODEM_LOW) && + (uuid->timeMid == UUID_TEE_TA_START_MODEM_MID) && + (uuid->timeHiAndVersion == UUID_TEE_TA_START_MODEM_HIGH)) { + + u8 clockSeqAndNode[TEE_UUID_CLOCK_SIZE] = + UUID_TEE_TA_START_MODEM_CLOCKSEQ; + + ret = memcmp(uuid->clockSeqAndNode, clockSeqAndNode, + TEE_UUID_CLOCK_SIZE); + } + + return ret; +} + +int svp_call_sec_world(struct tee_session *ts, int sec_cmd) +{ + int ret = 0; + + if (ts == NULL) + return -EINVAL; + + if (cmp_uuid_start_modem(ts->uuid)) + return -EINVAL; + + switch (ts->cmd) { + case COMMAND_ID_START_MODEM: + ret = tee_ta_start_modem((struct tee_ta_start_modem *) + ts->op); + if (ret) { + ts->err = TEED_ERROR_GENERIC; + ts->origin = TEED_ORIGIN_TEE_APPLICATION; + pr_err("tee_ta_start_modem() failed!\n"); + return ret; + } + break; + + default: + break; + } + + /* TODO: to handle more trusted applications. */ + + return ret; +} diff --git a/arch/arm/mach-ux500/tee_ta_start_modem_svp.c b/arch/arm/mach-ux500/tee_ta_start_modem_svp.c new file mode 100644 index 00000000000..12337b93154 --- /dev/null +++ b/arch/arm/mach-ux500/tee_ta_start_modem_svp.c @@ -0,0 +1,56 @@ +/* + * Trusted application for starting the modem. + * + * Copyright (C) ST-Ericsson SA 2010 + * Author: Shujuan Chen <shujuan.chen@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/elf.h> +#include <mach/hardware.h> + +#include "mach/tee_ta_start_modem.h" + +static int reset_modem(unsigned long modem_start_addr) +{ + void __iomem *base = ioremap(U5500_ACCCON_BASE_SEC, 0x2FF); + if (!base) + return -ENOMEM; + + pr_info("[%s] Setting modem start address!\n", __func__); + writel(base + (U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET/sizeof(uint32_t)), + modem_start_addr); + + pr_info("[%s] resetting the modem!\n", __func__); + writel(base + (U5500_ACCCON_ACC_CPU_CTRL_OFFSET/sizeof(uint32_t)), 1); + + iounmap(base); + + return 0; +} + +int tee_ta_start_modem(struct tee_ta_start_modem *data) +{ + int ret = 0; + struct elfhdr *elfhdr; + void __iomem *vaddr; + + vaddr = ioremap((unsigned long)data->access_image_descr.elf_hdr, + sizeof(struct elfhdr)); + if (!vaddr) + return -ENOMEM; + + elfhdr = (struct elfhdr *)readl(vaddr); + pr_info("Reading in kernel:elfhdr 0x%x:elfhdr->entry=0x%x\n", + (uint32_t)elfhdr, (uint32_t)elfhdr->e_entry); + + pr_info("[%s] reset modem()...\n", __func__); + ret = reset_modem(elfhdr->e_entry); + + iounmap(vaddr); + + return ret; +} diff --git a/arch/arm/mach-ux500/tee_ux500.c b/arch/arm/mach-ux500/tee_ux500.c new file mode 100644 index 00000000000..8b271913db1 --- /dev/null +++ b/arch/arm/mach-ux500/tee_ux500.c @@ -0,0 +1,112 @@ +/* + * TEE service to handle the calls to trusted applications. + * + * Copyright (C) ST-Ericsson SA 2010 + * Author: Joakim Bech <joakim.xx.bech@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ +#include <linux/kernel.h> +#include <linux/tee.h> +#include <linux/io.h> +#include <linux/errno.h> + +#include <mach/hardware.h> + +#ifdef CONFIG_UX500_SVP +extern int svp_call_sec_world(struct tee_session *ts, int sec_cmd); +#else +static int svp_call_sec_world(struct tee_session *ts, int sec_cmd) +{ + return -EINVAL; +} +#endif + +#define ISSWAPI_EXECUTE_TA 0x11000001 +#define ISSWAPI_CLOSE_TA 0x11000002 + +#define SEC_ROM_NO_FLAG_MASK 0x0000 + +static u32 call_sec_rom_bridge(u32 service_id, u32 cfg, ...) +{ + typedef u32 (*bridge_func)(u32, u32, va_list); + bridge_func hw_sec_rom_pub_bridge; + va_list ap; + u32 ret; + + if (cpu_is_u8500v2()) + hw_sec_rom_pub_bridge = (bridge_func) + ((u32)IO_ADDRESS(U8500_BOOT_ROM_BASE + 0x17300)); + else if (cpu_is_u8500v1()) + hw_sec_rom_pub_bridge = (bridge_func) + ((u32)IO_ADDRESS(U8500_BOOT_ROM_BASE + 0x18300)); + else if (cpu_is_u5500()) + hw_sec_rom_pub_bridge = (bridge_func) + ((u32)IO_ADDRESS(U5500_BOOT_ROM_BASE + 0x18300)); + else { + pr_err("tee-ux500: Unknown DB Asic!\n"); + return -EIO; + } + + va_start(ap, cfg); + ret = hw_sec_rom_pub_bridge(service_id, cfg, ap); + va_end(ap); + + return ret; +} + +int call_sec_world(struct tee_session *ts, int sec_cmd) +{ + if (ux500_is_svp()) + return svp_call_sec_world(ts, sec_cmd); + + /* + * ts->ta and ts->uuid is set to NULL when opening the device, + * hence it should be safe to just do the call here. + */ + + switch (sec_cmd) { + case TEED_INVOKE: + if (!ts->uuid) { + call_sec_rom_bridge(ISSWAPI_EXECUTE_TA, + SEC_ROM_NO_FLAG_MASK, + virt_to_phys(&ts->id), + NULL, + virt_to_phys(ts->ta), + ts->cmd, + virt_to_phys((void *)(ts->op)), + virt_to_phys((void *)(&ts->err)), + virt_to_phys((void *)(&ts->origin))); + } else { + call_sec_rom_bridge(ISSWAPI_EXECUTE_TA, + SEC_ROM_NO_FLAG_MASK, + virt_to_phys(&ts->id), + virt_to_phys(ts->uuid), + virt_to_phys(ts->ta), + ts->cmd, + virt_to_phys((void *)(ts->op)), + virt_to_phys((void *)(&ts->err)), + virt_to_phys((void *)(&ts->origin))); + } + break; + + case TEED_CLOSE_SESSION: + call_sec_rom_bridge(ISSWAPI_CLOSE_TA, + SEC_ROM_NO_FLAG_MASK, + ts->id, + NULL, + virt_to_phys(ts->ta), + virt_to_phys((void *)(&ts->err))); + + /* Since the TEE Client API does NOT take care of + * the return value, we print a warning here if + * something went wrong in secure world. + */ + if (ts->err != TEED_SUCCESS) + pr_warning("[%s] failed in secure world\n", + __func__); + + break; + } + + return 0; +} diff --git a/arch/arm/mach-ux500/timer-db8500-prcmu.c b/arch/arm/mach-ux500/timer-db8500-prcmu.c new file mode 100644 index 00000000000..606efa3c0f8 --- /dev/null +++ b/arch/arm/mach-ux500/timer-db8500-prcmu.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson + * sched_clock implementation is based on: + * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com> + * + * DB8500-PRCMU Timer + * The PRCMU has 5 timers which are available in a always-on + * power domain. we use the Timer 4 for our always-on clock source. + */ +#include <linux/clockchips.h> +#include <linux/clk.h> +#include <linux/jiffies.h> +#include <linux/boottime.h> +#include <linux/cnt32_to_63.h> +#include <linux/sched.h> +#include <mach/setup.h> +#include <mach/db8500-regs.h> +#include <mach/hardware.h> + +#define RATE_32K (32768) + +#define TIMER_MODE_CONTINOUS (0x1) +#define TIMER_DOWNCOUNT_VAL (0xffffffff) + +/* PRCMU Timer 4 */ +#define PRCMU_TIMER_4_REF (prcmu_base + 0x450) +#define PRCMU_TIMER_4_DOWNCOUNT (prcmu_base + 0x454) +#define PRCMU_TIMER_4_MODE (prcmu_base + 0x458) + +static __iomem void *prcmu_base; + +#define SCHED_CLOCK_MIN_WRAP (131072) /* 2^32 / 32768 */ + +static cycle_t db8500_prcmu_read_timer_nop(struct clocksource *cs) +{ + return 0; +} + +static struct clocksource db8500_prcmu_clksrc = { + .name = "db8500-prcmu-timer4", + .rating = 300, + .read = db8500_prcmu_read_timer_nop, + .shift = 10, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static cycle_t db8500_prcmu_read_timer(struct clocksource *cs) +{ + u32 count, count2; + + do { + count = readl(PRCMU_TIMER_4_DOWNCOUNT); + count2 = readl(PRCMU_TIMER_4_DOWNCOUNT); + } while (count2 != count); + + /* + * clocksource: the prcmu timer is a decrementing counters, so we negate + * the value being read. + */ + return ~count; +} + +#ifdef CONFIG_U8500_PRCMU_TIMER +unsigned long long notrace sched_clock(void) +{ + return clocksource_cyc2ns(db8500_prcmu_clksrc.read( + &db8500_prcmu_clksrc), + db8500_prcmu_clksrc.mult, + db8500_prcmu_clksrc.shift); +} +#endif + +#ifdef CONFIG_BOOTTIME + +static unsigned long __init boottime_get_time(void) +{ + return div_s64(clocksource_cyc2ns(db8500_prcmu_clksrc.read( + &db8500_prcmu_clksrc), + db8500_prcmu_clksrc.mult, + db8500_prcmu_clksrc.shift), 1000); +} + +static struct boottime_timer __initdata boottime_timer = { + .init = NULL, + .get_time = boottime_get_time, + .finalize = NULL, +}; +#endif + +void __init db8500_prcmu_timer_init(void) +{ + if (ux500_is_svp()) + return; + + prcmu_base = __io_address(U8500_PRCMU_BASE); + + clocksource_calc_mult_shift(&db8500_prcmu_clksrc, + RATE_32K, SCHED_CLOCK_MIN_WRAP); + + /* + * The A9 sub system expects the timer to be configured as + * a continous looping timer. + * The PRCMU should configure it but if it for some reason + * don't we do it here. + */ + if (readl(PRCMU_TIMER_4_MODE) != TIMER_MODE_CONTINOUS) { + writel(TIMER_MODE_CONTINOUS, PRCMU_TIMER_4_MODE); + writel(TIMER_DOWNCOUNT_VAL, PRCMU_TIMER_4_REF); + } + db8500_prcmu_clksrc.read = db8500_prcmu_read_timer; + + clocksource_register(&db8500_prcmu_clksrc); + + if (!ux500_is_svp()) + boottime_activate(&boottime_timer); +} + diff --git a/arch/arm/mach-ux500/timer-db8500.c b/arch/arm/mach-ux500/timer-db8500.c new file mode 100644 index 00000000000..70ec8f6275c --- /dev/null +++ b/arch/arm/mach-ux500/timer-db8500.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson + */ +#include <linux/io.h> +#include <mach/setup.h> +#include <mach/hardware.h> + +#include "pm/context.h" + +void u8500_rtc_init(unsigned int cpu); +void db8500_prcmu_timer_init(void); +void mtu_timer_init(void); +void mtu_clocksource_reset(void); +void mtu_clockevent_reset(void); + +#ifdef CONFIG_LOCAL_TIMERS +extern void *twd_base; +#endif + +#ifdef CONFIG_UX500_CONTEXT +static int mtu_context_notifier_call(struct notifier_block *this, + unsigned long event, void *data) +{ + if (event == CONTEXT_APE_RESTORE) + mtu_clocksource_reset(); + return NOTIFY_OK; +} + +static struct notifier_block mtu_context_notifier = { + .notifier_call = mtu_context_notifier_call, +}; +#endif + +static void u8500_timer_reset(void) +{ + mtu_clockevent_reset(); +} + +static void __init u8500_timer_init(void) +{ + +#ifdef CONFIG_LOCAL_TIMERS + if (cpu_is_u5500()) + twd_base = __io_address(U5500_TWD_BASE); + else if (cpu_is_u8500()) + twd_base = __io_address(U8500_TWD_BASE); + else + ux500_unknown_soc(); +#endif +/* + * Here we register the timerblocks active in the system. + * Localtimers (twd) is started when both cpu is up and running. + * MTU register a clocksource, clockevent and sched_clock. + * Since the MTU is located in the VAPE power domain + * it will be cleared in sleep which makes it unsuitable. + * We however need it as a timer tick (clockevent) + * during boot to calibrate delay until twd is started. + * RTC-RTT have problems as timer tick during boot since it is depending + * on delay which is not yet calibrated. RTC-RTT is in the always-on + * powerdomain and is used as clockevent instead of twd when sleeping. + * The PRCMU timer 4 register a clocksource and sched_clock with higher + * rating then MTU since is always-on. + * + */ + mtu_timer_init(); +#ifdef CONFIG_U8500_PRCMU + u8500_rtc_init(0); + db8500_prcmu_timer_init(); +#endif + +#ifdef CONFIG_UX500_CONTEXT + WARN_ON(context_ape_notifier_register(&mtu_context_notifier)); +#endif +} + +struct sys_timer u8500_timer = { + .init = u8500_timer_init, + .resume = u8500_timer_reset, +}; diff --git a/arch/arm/mach-ux500/timer-mtu.c b/arch/arm/mach-ux500/timer-mtu.c new file mode 100644 index 00000000000..51778245515 --- /dev/null +++ b/arch/arm/mach-ux500/timer-mtu.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2008 STMicroelectronics + * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x + * Copyright (C) 2009 ST-Ericsson SA + * added support to u8500 platform, heavily based on 8815 + * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/clockchips.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/jiffies.h> +#include <linux/boottime.h> +#include <linux/cnt32_to_63.h> +#include <asm/mach/time.h> + +#include <mach/setup.h> + +#define MTU_IMSC 0x00 /* Interrupt mask set/clear */ +#define MTU_RIS 0x04 /* Raw interrupt status */ +#define MTU_MIS 0x08 /* Masked interrupt status */ +#define MTU_ICR 0x0C /* Interrupt clear register */ + +/* per-timer registers take 0..3 as argument */ +#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */ +#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */ +#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */ +#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */ + +/* bits for the control register */ +#define MTU_CRn_ENA (0x01 << 7) +#define MTU_CRn_DIS (0x00 << 7) +#define MTU_CRn_PERIODIC (0x01 << 6) /* if 0 = free-running */ +#define MTU_CRn_FREERUNNING (0x00 << 6) +#define MTU_CRn_PRESCALE_MASK (0x03 << 2) +#define MTU_CRn_PRESCALE_1 (0x00 << 2) +#define MTU_CRn_PRESCALE_16 (0x01 << 2) +#define MTU_CRn_PRESCALE_256 (0x02 << 2) +#define MTU_CRn_32BITS (0x01 << 1) + +/* if 0 = wraps reloading from BGLR*/ +#define MTU_CRn_ONESHOT (0x01 << 0) + +/* Other registers are usual amba/primecell registers, currently not used */ +#define MTU_ITCR 0xff0 +#define MTU_ITOP 0xff4 + +#define MTU_PERIPH_ID0 0xfe0 +#define MTU_PERIPH_ID1 0xfe4 +#define MTU_PERIPH_ID2 0xfe8 +#define MTU_PERIPH_ID3 0xfeC + +#define MTU_PCELL0 0xff0 +#define MTU_PCELL1 0xff4 +#define MTU_PCELL2 0xff8 +#define MTU_PCELL3 0xffC + +static u32 u8500_cycle; /* write-once */ +static __iomem void *mtu0_base; +static bool mtu_periodic; + +/* + * U8500 sched_clock implementation. It has a resolution of + * at least 7.5ns (133MHz MTU rate) and a maximum value of 834 days. + * + * Because the hardware timer period is quite short (32.3 secs + * and because cnt32_to_63() needs to be called at + * least once per half period to work properly, a kernel timer is + * set up to ensure this requirement is always met. + * + * Based on plat-orion time.c implementation. + */ +#define TCLK2NS_SCALE_FACTOR 8 + +#ifdef CONFIG_UX500_MTU_TIMER +static unsigned long tclk2ns_scale; +static struct timer_list cnt32_to_63_keepwarm_timer; + +unsigned long long sched_clock(void) +{ + unsigned long long v; + + if (unlikely(!mtu0_base)) + return 0; + + v = cnt32_to_63(0xffffffff - readl(mtu0_base + MTU_VAL(1))); + return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR; +} + +static void cnt32_to_63_keepwarm(unsigned long data) +{ + mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); + (void) sched_clock(); +} + +static void __init setup_sched_clock(unsigned long tclk) +{ + unsigned long long v; + unsigned long data; + + v = NSEC_PER_SEC; + v <<= TCLK2NS_SCALE_FACTOR; + v += tclk / 2; + do_div(v, tclk); + /* + * We want an even value to automatically clear the top bit + * returned by cnt32_to_63() without an additional run time + * instruction. So if the LSB is 1 then round it up. + */ + if (v & 1) + v++; + tclk2ns_scale = v; + + data = (0xffffffffUL / tclk / 2 - 2) * HZ; + setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data); + mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); +} +#else +static void __init setup_sched_clock(unsigned long tclk) +{ +} +#endif +/* + * clocksource: the MTU device is a decrementing counters, so we negate + * the value being read. + */ +static cycle_t u8500_read_timer(struct clocksource *cs) +{ + u32 count = readl(mtu0_base + MTU_VAL(1)); + return ~count; +} +/* + * Kernel assumes that sched_clock can be called early + * but the MTU may not yet be initialized. + */ +static cycle_t u8500_read_timer_dummy(struct clocksource *cs) +{ + return 0; +} + +void mtu_clocksource_reset(void) +{ + writel(MTU_CRn_DIS, mtu0_base + MTU_CR(1)); + + /* ClockSource: configure load and background-load, and fire it up */ + writel(u8500_cycle, mtu0_base + MTU_LR(1)); + writel(u8500_cycle, mtu0_base + MTU_BGLR(1)); + + writel(MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS | MTU_CRn_ENA | + MTU_CRn_FREERUNNING, mtu0_base + MTU_CR(1)); +} + +static struct clocksource u8500_clksrc = { + .name = "mtu_1", + .rating = 120, + .read = u8500_read_timer_dummy, + .shift = 20, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +#ifdef ARCH_HAS_READ_CURRENT_TIMER +void mtu_timer_delay_loop(unsigned long loops) +{ + unsigned long bclock, now; + + bclock = u8500_read_timer(&u8500_clksrc); + do { + now = u8500_read_timer(&u8500_clksrc); + /* If timer have been cleared (suspend) or wrapped we exit */ + if (unlikely(now < bclock)) + return; + } while ((now - bclock) < loops); +} + +/* Used to calibrate the delay */ +int read_current_timer(unsigned long *timer_val) +{ + *timer_val = u8500_read_timer(&u8500_clksrc); + return 0; +} +#endif + +/* + * Clockevent + */ +static int u8500_mtu_clkevt_next(unsigned long evt, struct clock_event_device *ev) +{ + writel(1 << 0, mtu0_base + MTU_IMSC); + writel(evt, mtu0_base + MTU_LR(0)); + /* Load highest value, enable device, enable interrupts */ + writel(MTU_CRn_ONESHOT | MTU_CRn_PRESCALE_1 | + MTU_CRn_32BITS | MTU_CRn_ENA, + mtu0_base + MTU_CR(0)); + return 0; +} + +void mtu_clockevent_reset(void) +{ + if (mtu_periodic) { + + /* Timer: configure load and background-load, and fire it up */ + writel(u8500_cycle, mtu0_base + MTU_LR(0)); + writel(u8500_cycle, mtu0_base + MTU_BGLR(0)); + + writel(MTU_CRn_PERIODIC | MTU_CRn_PRESCALE_1 | + MTU_CRn_32BITS | MTU_CRn_ENA, + mtu0_base + MTU_CR(0)); + writel(1 << 0, mtu0_base + MTU_IMSC); + } else { + /* Generate an interrupt to start the clockevent again */ + u8500_mtu_clkevt_next(u8500_cycle, NULL); + } +} + +static void u8500_mtu_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + mtu_periodic = true; + mtu_clockevent_reset(); + break; + case CLOCK_EVT_MODE_ONESHOT: + mtu_periodic = false; + break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + writel(MTU_CRn_DIS, mtu0_base + MTU_CR(0)); + writel(0, mtu0_base + MTU_IMSC); + break; + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +/* + * IRQ Handler for the timer 0 of the MTU block. The irq is not shared + * as we are the only users of mtu0 by now. + */ +static irqreturn_t u8500_timer_interrupt(int irq, void *dev) +{ + struct clock_event_device *clkevt = dev; + /* ack: "interrupt clear register" */ + writel(1 << 0, mtu0_base + MTU_ICR); + + clkevt->event_handler(clkevt); + + return IRQ_HANDLED; +} + +/* + * Added here as asm/smp.h is removed in v2.6.34 and + * this funcitons is needed for current PM setup. + */ +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +void smp_timer_broadcast(const struct cpumask *mask); +#endif + +struct clock_event_device u8500_mtu_clkevt = { + .name = "mtu_0", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + /* Must be of higher rating the timer-rtt but lower than localtimers */ + .rating = 310, + .set_mode = u8500_mtu_clkevt_mode, + .set_next_event = u8500_mtu_clkevt_next, + .irq = IRQ_MTU0, +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + .broadcast = smp_timer_broadcast, +#endif + .cpumask = cpu_all_mask, +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +static struct irqaction u8500_timer_irq = { + .name = "MTU Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = u8500_timer_interrupt, + .dev_id = &u8500_mtu_clkevt, +}; + +void __init mtu_timer_init(void) +{ + unsigned long rate; + struct clk *clk0; + + clk0 = clk_get_sys("mtu0", NULL); + BUG_ON(IS_ERR(clk0)); + + rate = clk_get_rate(clk0); + + clk_enable(clk0); + + /* + * Set scale and timer for sched_clock + */ + setup_sched_clock(rate); + u8500_cycle = (rate + HZ/2) / HZ; + + /* Save global pointer to mtu, used by functions above */ + if (cpu_is_u5500()) { + mtu0_base = ioremap(U5500_MTU0_BASE, SZ_4K); + } else if (cpu_is_u8500()) { + mtu0_base = ioremap(U8500_MTU0_BASE, SZ_4K); + } else { + ux500_unknown_soc(); + } + + /* Restart clock source */ + mtu_clocksource_reset(); + + /* Now the scheduling clock is ready */ + u8500_clksrc.read = u8500_read_timer; + u8500_clksrc.mult = clocksource_hz2mult(rate, u8500_clksrc.shift); + + clocksource_register(&u8500_clksrc); + + /* Register irq and clockevents */ + + /* We can sleep for max 10s (actually max is longer) */ + clockevents_calc_mult_shift(&u8500_mtu_clkevt, rate, 10); + + u8500_mtu_clkevt.max_delta_ns = clockevent_delta2ns(0xffffffff, + &u8500_mtu_clkevt); + u8500_mtu_clkevt.min_delta_ns = clockevent_delta2ns(0xff, + &u8500_mtu_clkevt); + + setup_irq(IRQ_MTU0, &u8500_timer_irq); + clockevents_register_device(&u8500_mtu_clkevt); +#ifdef ARCH_HAS_READ_CURRENT_TIMER + set_delay_fn(mtu_timer_delay_loop); +#endif +} diff --git a/arch/arm/mach-ux500/timer-rtt.c b/arch/arm/mach-ux500/timer-rtt.c new file mode 100644 index 00000000000..e13ea25195f --- /dev/null +++ b/arch/arm/mach-ux500/timer-rtt.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Rabin Vincent <rabin.vincent@stericsson.com> + * + * NOTE: This timer is optimized to be used from cpuidle only, so + * if you enable this timer as broadcast timer, it won't work. + * + */ +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/clockchips.h> + +#include <asm/smp.h> +#include <asm/mach/time.h> + +#define RATE_32K 32768 + +#define RTC_IMSC 0x10 +#define RTC_MIS 0x18 +#define RTC_ICR 0x1C +#define RTC_TDR 0x20 +#define RTC_TLR1 0x24 +#define RTC_TCR 0x28 + +#define RTC_TCR_RTTOS (1 << 0) +#define RTC_TCR_RTTEN (1 << 1) +#define RTC_TCR_RTTSS (1 << 2) + +#define RTC_IMSC_TIMSC (1 << 1) +#define RTC_ICR_TIC (1 << 1) +#define RTC_MIS_RTCTMIS (1 << 1) + +static void __iomem *rtc_base; + +static void u8500_rtc_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + pr_err("timer-rtt: periodic timer not supported\n"); + case CLOCK_EVT_MODE_ONESHOT: + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* Disable, self start and oneshot mode */ + writel(RTC_TCR_RTTSS | RTC_TCR_RTTOS, rtc_base + RTC_TCR); + /* + * Here you should actually wait for 130 us before + * touching RTC_TCR again. + */ + break; + + case CLOCK_EVT_MODE_RESUME: + break; + + } +} + +static int u8500_rtc_set_event(unsigned long delta, + struct clock_event_device *dev) +{ + /* + * Here you must be sure that the timer is off or else + * you'll probably fail programming it. + */ + writel(delta, rtc_base + RTC_TLR1); + + /* Here you must be sure not to touch TCR for 130 us */ + + return 0; +} + +static irqreturn_t u8500_rtc_interrupt(int irq, void *dev) +{ + + /* we make sure if this is our rtt isr */ + if (readl(rtc_base + RTC_MIS) & RTC_MIS_RTCTMIS) { + writel(RTC_ICR_TIC, rtc_base + RTC_ICR); + /* Here you should normally call the event handler */ + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/* + * Added here as asm/smp.h is removed in v2.6.34 and + * this funcitons is needed for current PM setup. + */ +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +void smp_timer_broadcast(const struct cpumask *mask); +#endif + +struct clock_event_device u8500_rtt_clkevt = { + .name = "rtc-rtt", + .features = CLOCK_EVT_FEAT_ONESHOT, + /* This timer is not working except from cpuidle */ + .rating = 0, + .set_next_event = u8500_rtc_set_event, + .set_mode = u8500_rtc_set_mode, +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + .broadcast = smp_timer_broadcast, +#endif + .cpumask = cpu_all_mask, +}; + +extern struct clock_event_device u8500_mtu_clkevt; +static struct irqaction u8500_rtc_irq = { + .name = "RTC-RTT Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_SHARED, + .handler = u8500_rtc_interrupt, + .irq = IRQ_DB8500_RTC, +}; + +void u8500_rtc_init(unsigned int cpu) +{ + + if (cpu_is_u8500()) { + rtc_base = __io_address(U8500_RTC_BASE); + } else if (cpu_is_u5500()) { + rtc_base = __io_address(U5500_RTC_BASE); + u8500_rtt_clkevt.irq = IRQ_DB5500_RTC; + } else { + pr_err("timer-rtt: Unknown DB Asic!\n"); + return; + } + + writel(RTC_TCR_RTTSS | RTC_TCR_RTTOS, rtc_base + RTC_TCR); + writel(RTC_ICR_TIC, rtc_base + RTC_ICR); + writel(RTC_IMSC_TIMSC, rtc_base + RTC_IMSC); + + /* We can sleep for max 10s (actually max is longer) */ + clockevents_calc_mult_shift(&u8500_rtt_clkevt, RATE_32K, 10); + + u8500_rtt_clkevt.max_delta_ns = clockevent_delta2ns(0xffffffff, + &u8500_rtt_clkevt); + /* Don't program times less than eight cycles */ + u8500_rtt_clkevt.min_delta_ns = clockevent_delta2ns(8, + &u8500_rtt_clkevt); + setup_irq(u8500_rtc_irq.irq, &u8500_rtc_irq); + clockevents_register_device(&u8500_rtt_clkevt); +} diff --git a/arch/arm/mach-ux500/uart-db8500.c b/arch/arm/mach-ux500/uart-db8500.c new file mode 100644 index 00000000000..a2836da9cec --- /dev/null +++ b/arch/arm/mach-ux500/uart-db8500.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Arun R Murthy <arun.murthy@stericsson.com>, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/amba/serial.h> +#include <mach/setup.h> +#include <mach/hardware.h> + +#include "pm/context.h" + +#ifdef CONFIG_UX500_CONTEXT + +#define UX500_NR_UARTS 3 + +static struct { + struct clk *uart_clk; + void __iomem *base; + /* dr */ + /* rsr_err */ + u32 dma_wm; + u32 timeout; + /* fr */ + u32 lcrh_rx; + u32 ilpr; + u32 ibrd; + u32 fbrd; + u32 lcrh_tx; + u32 cr; + u32 ifls; + u32 imsc; + /* ris */ + /* mis */ + /* icr */ + u32 dmacr; + u32 xfcr; + u32 xon1; + u32 xon2; + u32 xoff1; + u32 xoff2; + /* itcr */ + /* itip */ + /* itop */ + /* tdr */ + u32 abcr; + /* absr */ + /* abfmt */ + /* abdr */ + /* abdfr */ + /* abmr */ + u32 abimsc; + /* abris */ + /* abmis */ + /* abicr */ + /* id_product_h_xy */ + /* id_provider */ + /* periphid0 */ + /* periphid1 */ + /* periphid2 */ + /* periphid3 */ + /* pcellid0 */ + /* pcellid1 */ + /* pcellid2 */ + /* pcellid3 */ +} context_uart[UX500_NR_UARTS]; + + +static void save_uart(void) +{ + int i; + void __iomem *membase; + + for (i = 0; i < UX500_NR_UARTS; i++) { + if (i != CONFIG_UX500_DEBUG_UART) + continue; + + membase = context_uart[i].base; + clk_enable(context_uart[i].uart_clk); + + context_uart[i].dma_wm = readl(membase + ST_UART011_DMAWM); + context_uart[i].timeout = readl(membase + ST_UART011_TIMEOUT); + context_uart[i].lcrh_rx = readl(membase + ST_UART011_LCRH_RX); + context_uart[i].ilpr = readl(membase + UART01x_ILPR); + context_uart[i].ibrd = readl(membase + UART011_IBRD); + context_uart[i].fbrd = readl(membase + UART011_FBRD); + context_uart[i].lcrh_tx = readl(membase + ST_UART011_LCRH_TX); + context_uart[i].cr = readl(membase + UART011_CR); + context_uart[i].ifls = readl(membase + UART011_IFLS); + context_uart[i].imsc = readl(membase + UART011_IMSC); + context_uart[i].dmacr = readl(membase + UART011_DMACR); + context_uart[i].xfcr = readl(membase + ST_UART011_XFCR); + context_uart[i].xon1 = readl(membase + ST_UART011_XON1); + context_uart[i].xon2 = readl(membase + ST_UART011_XON2); + context_uart[i].xoff1 = readl(membase + ST_UART011_XOFF1); + context_uart[i].xoff2 = readl(membase + ST_UART011_XOFF2); + context_uart[i].abcr = readl(membase + ST_UART011_ABCR); + context_uart[i].abimsc = readl(membase + ST_UART011_ABIMSC); + + clk_disable(context_uart[i].uart_clk); + } +} + +static void restore_uart(void) +{ + int i, cnt; + int retries = 100; + unsigned int cr; + void __iomem *membase; + + for (i = 0; i < UX500_NR_UARTS; i++) { + if (i != CONFIG_UX500_DEBUG_UART) + continue; + + membase = context_uart[i].base; + clk_enable(context_uart[i].uart_clk); + + writew(context_uart[i].ifls, membase + UART011_IFLS); + cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; + + writew(cr, membase + UART011_CR); + writew(0, membase + UART011_FBRD); + writew(1, membase + UART011_IBRD); + writew(0, membase + ST_UART011_LCRH_RX); + if (context_uart[i].lcrh_tx != ST_UART011_LCRH_RX) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, membase + UART011_MIS); + writew(0, membase + ST_UART011_LCRH_TX); + } + writew(0, membase + UART01x_DR); + do { + if (!(readw(membase + UART01x_FR) & UART01x_FR_BUSY)) + break; + } while (retries-- > 0); + if (retries < 0) + pr_warning("%s:uart tx busy\n", __func__); + barrier(); + + writel(context_uart[i].dma_wm, membase + ST_UART011_DMAWM); + writel(context_uart[i].timeout, membase + ST_UART011_TIMEOUT); + writel(context_uart[i].lcrh_rx, membase + ST_UART011_LCRH_RX); + writel(context_uart[i].ilpr, membase + UART01x_ILPR); + writel(context_uart[i].ibrd, membase + UART011_IBRD); + writel(context_uart[i].fbrd, membase + UART011_FBRD); + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10-3 + * times, as already there are 3 writes after + * ST_UART011_LCRH_RX + */ + for (cnt = 0; cnt < 7; cnt++) + writew(0xff, membase + UART011_MIS); + + writel(context_uart[i].lcrh_tx, membase + ST_UART011_LCRH_TX); + writel(context_uart[i].ifls, membase + UART011_IFLS); + writel(context_uart[i].dmacr, membase + UART011_DMACR); + writel(context_uart[i].xfcr, membase + ST_UART011_XFCR); + writel(context_uart[i].xon1, membase + ST_UART011_XON1); + writel(context_uart[i].xon2, membase + ST_UART011_XON2); + writel(context_uart[i].xoff1, membase + ST_UART011_XOFF1); + writel(context_uart[i].xoff2, membase + ST_UART011_XOFF2); + writel(context_uart[i].abcr, membase + ST_UART011_ABCR); + writel(context_uart[i].abimsc, membase + ST_UART011_ABIMSC); + writel(context_uart[i].cr, membase + UART011_CR); + writel(context_uart[i].imsc, membase + UART011_IMSC); + + clk_disable(context_uart[i].uart_clk); + } +} + + +static int uart_context_notifier_call(struct notifier_block *this, + unsigned long event, void *data) +{ + switch (event) { + case CONTEXT_APE_SAVE: + save_uart(); + break; + + case CONTEXT_APE_RESTORE: + restore_uart(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block uart_context_notifier = { + .notifier_call = uart_context_notifier_call, +}; + +static void uart_context_notifier_init(void) +{ + context_uart[0].base = ioremap(U8500_UART0_BASE, SZ_4K); + context_uart[1].base = ioremap(U8500_UART1_BASE, SZ_4K); + context_uart[2].base = ioremap(U8500_UART2_BASE, SZ_4K); + + context_uart[0].uart_clk = clk_get_sys("uart0", NULL); + if (IS_ERR(context_uart[0].uart_clk)) { + printk(KERN_ERR"%s:unable to get clk-uart0\n", __func__); + return; + } + context_uart[1].uart_clk = clk_get_sys("uart1", NULL); + if (IS_ERR(context_uart[1].uart_clk)) { + printk(KERN_ERR"%s:unable to get clk-uart1\n", __func__); + return; + } + context_uart[2].uart_clk = clk_get_sys("uart2", NULL); + if (IS_ERR(context_uart[2].uart_clk)) { + printk(KERN_ERR"%s:unable to get clk-uart2\n", __func__); + return; + } + + WARN_ON(context_ape_notifier_register(&uart_context_notifier)); +} +#else +static void uart_context_notifier_init(void) +{ +} +#endif + +void __init db8500_uart_init(void) +{ + uart_context_notifier_init(); +} diff --git a/arch/arm/mach-ux500/virt-regulator-u8500.c b/arch/arm/mach-ux500/virt-regulator-u8500.c new file mode 100644 index 00000000000..4915a4cf636 --- /dev/null +++ b/arch/arm/mach-ux500/virt-regulator-u8500.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * Board specific file for configuration of virtual regulators. These virtual + * regulators are used for debug purposes. They connect to the regulator device + * just like any other consumer and expose controls in sysfs, so that + * regulators can be controlled from user space. + */ + +#include <linux/init.h> +#include <linux/platform_device.h> + +/* + * Configuration for AB8500 virtual regulators + */ +static struct platform_device u8500_aux1_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 0, + .dev = { + .platform_data = "aux1", + }, +}; + +static struct platform_device u8500_aux2_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 1, + .dev = { + .platform_data = "aux2", + }, +}; + +static struct platform_device u8500_aux3_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 2, + .dev = { + .platform_data = "aux3", + }, +}; + +static struct platform_device u8500_intcore_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 3, + .dev = { + .platform_data = "intcore", + }, +}; + +static struct platform_device u8500_tvout_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 4, + .dev = { + .platform_data = "tvout", + }, +}; + +static struct platform_device u8500_audio_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 5, + .dev = { + .platform_data = "audio", + }, +}; + +static struct platform_device u8500_anamic1_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 6, + .dev = { + .platform_data = "anamic1", + }, +}; + +static struct platform_device u8500_anamic2_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 7, + .dev = { + .platform_data = "anamic2", + }, +}; + +static struct platform_device u8500_dmic_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 8, + .dev = { + .platform_data = "dmic", + }, +}; + +static struct platform_device u8500_ana_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 9, + .dev = { + .platform_data = "ana", + }, +}; + +static struct platform_device u8500_sysclkreq_2_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 10, + .dev = { + .platform_data = "sysclkreq-2", + }, +}; + +static struct platform_device u8500_sysclkreq_4_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 11, + .dev = { + .platform_data = "sysclkreq-4", + }, +}; + +/* + * Configuration for other U8500 virtual regulators + */ +static struct platform_device u8500_ape_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 12, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_arm_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 13, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_modem_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 14, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_pll_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 15, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_smps1_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 16, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_smps2_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 17, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_smps3_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 18, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_rf1_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 19, + .dev = { + .platform_data = "test", + }, +}; + +/* + * Configuration for U8500 power domain virtual regulators + */ +static struct platform_device u8500_sva_mmdsp_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 20, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sva_mmdsp_ret_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 21, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sva_pipe_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 22, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sia_mmdsp_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 23, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sia_mmdsp_ret_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 24, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sia_pipe_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 25, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_sga_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 26, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_b2r2_mcde_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 27, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_esram12_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 28, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_esram12_ret_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 29, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_esram34_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 30, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device u8500_esram34_ret_virtual_regulator_device = { + .name = "reg-virt-consumer", + .id = 31, + .dev = { + .platform_data = "test", + }, +}; + +static struct platform_device *u8500_virtual_regulator_devices[] = { + &u8500_aux1_virtual_regulator_device, + &u8500_aux2_virtual_regulator_device, + &u8500_aux3_virtual_regulator_device, + &u8500_intcore_virtual_regulator_device, + &u8500_tvout_virtual_regulator_device, + &u8500_audio_virtual_regulator_device, + &u8500_anamic1_virtual_regulator_device, + &u8500_anamic2_virtual_regulator_device, + &u8500_dmic_virtual_regulator_device, + &u8500_ana_virtual_regulator_device, + &u8500_sysclkreq_2_virtual_regulator_device, + &u8500_sysclkreq_4_virtual_regulator_device, + &u8500_ape_virtual_regulator_device, + &u8500_arm_virtual_regulator_device, + &u8500_modem_virtual_regulator_device, + &u8500_pll_virtual_regulator_device, + &u8500_smps1_virtual_regulator_device, + &u8500_smps2_virtual_regulator_device, + &u8500_smps3_virtual_regulator_device, + &u8500_rf1_virtual_regulator_device, + &u8500_sva_mmdsp_virtual_regulator_device, + &u8500_sva_mmdsp_ret_virtual_regulator_device, + &u8500_sva_pipe_virtual_regulator_device, + &u8500_sia_mmdsp_virtual_regulator_device, + &u8500_sia_mmdsp_ret_virtual_regulator_device, + &u8500_sia_pipe_virtual_regulator_device, + &u8500_sga_virtual_regulator_device, + &u8500_b2r2_mcde_virtual_regulator_device, + &u8500_esram12_virtual_regulator_device, + &u8500_esram12_ret_virtual_regulator_device, + &u8500_esram34_virtual_regulator_device, + &u8500_esram34_ret_virtual_regulator_device, +}; + +static int __init u8500_virtual_regulator_init(void) +{ + int ret; + + ret = platform_add_devices(u8500_virtual_regulator_devices, + ARRAY_SIZE(u8500_virtual_regulator_devices)); + if (ret != 0) + pr_err("Failed to register U8500 virtual regulator devices:" + " %d\n", ret); + + return ret; +} +module_init(u8500_virtual_regulator_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com"); +MODULE_DESCRIPTION("Configuration of u8500 virtual regulators"); +MODULE_ALIAS("platform:u8500-virtual-regulator"); |