From 5ad73d07173e7b76c16bcb8b6cf64d8386019689 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 10 Aug 2009 12:51:56 +0100 Subject: ARM: 5665/1: U300 syscon register updates This adds in a few new register and defines for improved padmux support and some figures that were plain wrong on the targeted U300 platforms. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/include/mach/syscon.h | 120 +++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h index 1c90d1b1ccb..7444f5c7da9 100644 --- a/arch/arm/mach-u300/include/mach/syscon.h +++ b/arch/arm/mach-u300/include/mach/syscon.h @@ -240,8 +240,13 @@ #define U300_SYSCON_PMC1LR_CDI_MASK (0xC000) #define U300_SYSCON_PMC1LR_CDI_CDI (0x0000) #define U300_SYSCON_PMC1LR_CDI_EMIF (0x4000) +#ifdef CONFIG_MACH_U300_BS335 +#define U300_SYSCON_PMC1LR_CDI_CDI2 (0x8000) +#define U300_SYSCON_PMC1LR_CDI_WCDMA_APP_GPIO (0xC000) +#elif CONFIG_MACH_U300_BS365 #define U300_SYSCON_PMC1LR_CDI_GPIO (0x8000) #define U300_SYSCON_PMC1LR_CDI_WCDMA (0xC000) +#endif #define U300_SYSCON_PMC1LR_PDI_MASK (0x3000) #define U300_SYSCON_PMC1LR_PDI_PDI (0x0000) #define U300_SYSCON_PMC1LR_PDI_EGG (0x1000) @@ -345,19 +350,69 @@ #define U300_SYSCON_MMCR_MASK (0x0003) #define U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE (0x0002) #define U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE (0x0001) - +/* Pull up/down control (R/W) */ +#define U300_SYSCON_PUCR (0x104) +#define U300_SYSCON_PUCR_EMIF_1_WAIT_N_PU_ENABLE (0x0200) +#define U300_SYSCON_PUCR_EMIF_1_NFIF_READY_PU_ENABLE (0x0100) +#define U300_SYSCON_PUCR_EMIF_1_16BIT_PU_ENABLE (0x0080) +#define U300_SYSCON_PUCR_EMIF_1_8BIT_PU_ENABLE (0x0040) +#define U300_SYSCON_PUCR_KEY_IN_PU_EN_MASK (0x003F) +/* Padmux 2 control */ +#define U300_SYSCON_PMC2R (0x100) +#define U300_SYSCON_PMC2R_APP_MISC_0_MASK (0x00C0) +#define U300_SYSCON_PMC2R_APP_MISC_0_APP_GPIO (0x0000) +#define U300_SYSCON_PMC2R_APP_MISC_0_EMIF_SDRAM (0x0040) +#define U300_SYSCON_PMC2R_APP_MISC_0_MMC (0x0080) +#define U300_SYSCON_PMC2R_APP_MISC_0_CDI2 (0x00C0) +#define U300_SYSCON_PMC2R_APP_MISC_1_MASK (0x0300) +#define U300_SYSCON_PMC2R_APP_MISC_1_APP_GPIO (0x0000) +#define U300_SYSCON_PMC2R_APP_MISC_1_EMIF_SDRAM (0x0100) +#define U300_SYSCON_PMC2R_APP_MISC_1_MMC (0x0200) +#define U300_SYSCON_PMC2R_APP_MISC_1_CDI2 (0x0300) +#define U300_SYSCON_PMC2R_APP_MISC_2_MASK (0x0C00) +#define U300_SYSCON_PMC2R_APP_MISC_2_APP_GPIO (0x0000) +#define U300_SYSCON_PMC2R_APP_MISC_2_EMIF_SDRAM (0x0400) +#define U300_SYSCON_PMC2R_APP_MISC_2_MMC (0x0800) +#define U300_SYSCON_PMC2R_APP_MISC_2_CDI2 (0x0C00) +#define U300_SYSCON_PMC2R_APP_MISC_3_MASK (0x3000) +#define U300_SYSCON_PMC2R_APP_MISC_3_APP_GPIO (0x0000) +#define U300_SYSCON_PMC2R_APP_MISC_3_EMIF_SDRAM (0x1000) +#define U300_SYSCON_PMC2R_APP_MISC_3_MMC (0x2000) +#define U300_SYSCON_PMC2R_APP_MISC_3_CDI2 (0x3000) +#define U300_SYSCON_PMC2R_APP_MISC_4_MASK (0xC000) +#define U300_SYSCON_PMC2R_APP_MISC_4_APP_GPIO (0x0000) +#define U300_SYSCON_PMC2R_APP_MISC_4_EMIF_SDRAM (0x4000) +#define U300_SYSCON_PMC2R_APP_MISC_4_MMC (0x8000) +#define U300_SYSCON_PMC2R_APP_MISC_4_ACC_GPIO (0xC000) /* TODO: More SYSCON registers missing */ #define U300_SYSCON_PMC3R (0x10c) #define U300_SYSCON_PMC3R_APP_MISC_11_MASK (0xc000) #define U300_SYSCON_PMC3R_APP_MISC_11_SPI (0x4000) #define U300_SYSCON_PMC3R_APP_MISC_10_MASK (0x3000) #define U300_SYSCON_PMC3R_APP_MISC_10_SPI (0x1000) -/* TODO: Missing other configs, I just added the SPI stuff */ - +/* TODO: Missing other configs */ +#define U300_SYSCON_PMC4R (0x168) +#define U300_SYSCON_PMC4R_APP_MISC_12_MASK (0x0003) +#define U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO (0x0000) +#define U300_SYSCON_PMC4R_APP_MISC_13_MASK (0x000C) +#define U300_SYSCON_PMC4R_APP_MISC_13_CDI (0x0000) +#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA (0x0004) +#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA2 (0x0008) +#define U300_SYSCON_PMC4R_APP_MISC_13_APP_GPIO (0x000C) +#define U300_SYSCON_PMC4R_APP_MISC_14_MASK (0x0030) +#define U300_SYSCON_PMC4R_APP_MISC_14_CDI (0x0000) +#define U300_SYSCON_PMC4R_APP_MISC_14_SMIA (0x0010) +#define U300_SYSCON_PMC4R_APP_MISC_14_CDI2 (0x0020) +#define U300_SYSCON_PMC4R_APP_MISC_14_APP_GPIO (0x0030) +#define U300_SYSCON_PMC4R_APP_MISC_16_MASK (0x0300) +#define U300_SYSCON_PMC4R_APP_MISC_16_APP_GPIO_13 (0x0000) +#define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS (0x0100) +#define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N (0x0200) /* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */ #define U300_SYSCON_S0CCR (0x120) #define U300_SYSCON_S0CCR_FIELD_MASK (0x43FF) #define U300_SYSCON_S0CCR_CLOCK_REQ (0x4000) +#define U300_SYSCON_S0CCR_CLOCK_REQ_MONITOR (0x2000) #define U300_SYSCON_S0CCR_CLOCK_INV (0x0200) #define U300_SYSCON_S0CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S0CCR_CLOCK_SELECT_MASK (0x001E) @@ -375,6 +430,7 @@ #define U300_SYSCON_S1CCR (0x124) #define U300_SYSCON_S1CCR_FIELD_MASK (0x43FF) #define U300_SYSCON_S1CCR_CLOCK_REQ (0x4000) +#define U300_SYSCON_S1CCR_CLOCK_REQ_MONITOR (0x2000) #define U300_SYSCON_S1CCR_CLOCK_INV (0x0200) #define U300_SYSCON_S1CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S1CCR_CLOCK_SELECT_MASK (0x001E) @@ -393,6 +449,7 @@ #define U300_SYSCON_S2CCR_FIELD_MASK (0xC3FF) #define U300_SYSCON_S2CCR_CLK_STEAL (0x8000) #define U300_SYSCON_S2CCR_CLOCK_REQ (0x4000) +#define U300_SYSCON_S2CCR_CLOCK_REQ_MONITOR (0x2000) #define U300_SYSCON_S2CCR_CLOCK_INV (0x0200) #define U300_SYSCON_S2CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S2CCR_CLOCK_SELECT_MASK (0x001E) @@ -425,6 +482,44 @@ #define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_0_SDRAM (0x000C) #define U300_SYSCON_MCR_PM1G_MODE_ENABLE (0x0002) #define U300_SYSCON_MCR_PMTG5_MODE_ENABLE (0x0001) +/* SC_PLL_IRQ_CONTROL 16bit (R/W) */ +#define U300_SYSCON_PICR (0x0130) +#define U300_SYSCON_PICR_MASK (0x00FF) +#define U300_SYSCON_PICR_FORCE_PLL208_LOCK_LOW_ENABLE (0x0080) +#define U300_SYSCON_PICR_FORCE_PLL208_LOCK_HIGH_ENABLE (0x0040) +#define U300_SYSCON_PICR_FORCE_PLL13_LOCK_LOW_ENABLE (0x0020) +#define U300_SYSCON_PICR_FORCE_PLL13_LOCK_HIGH_ENABLE (0x0010) +#define U300_SYSCON_PICR_IRQMASK_PLL13_UNLOCK_ENABLE (0x0008) +#define U300_SYSCON_PICR_IRQMASK_PLL13_LOCK_ENABLE (0x0004) +#define U300_SYSCON_PICR_IRQMASK_PLL208_UNLOCK_ENABLE (0x0002) +#define U300_SYSCON_PICR_IRQMASK_PLL208_LOCK_ENABLE (0x0001) +/* SC_PLL_IRQ_STATUS 16 bit (R/-) */ +#define U300_SYSCON_PISR (0x0134) +#define U300_SYSCON_PISR_MASK (0x000F) +#define U300_SYSCON_PISR_PLL13_UNLOCK_IND (0x0008) +#define U300_SYSCON_PISR_PLL13_LOCK_IND (0x0004) +#define U300_SYSCON_PISR_PLL208_UNLOCK_IND (0x0002) +#define U300_SYSCON_PISR_PLL208_LOCK_IND (0x0001) +/* SC_PLL_IRQ_CLEAR 16 bit (-/W) */ +#define U300_SYSCON_PICLR (0x0138) +#define U300_SYSCON_PICLR_MASK (0x000F) +#define U300_SYSCON_PICLR_RWMASK (0x0000) +#define U300_SYSCON_PICLR_PLL13_UNLOCK_SC (0x0008) +#define U300_SYSCON_PICLR_PLL13_LOCK_SC (0x0004) +#define U300_SYSCON_PICLR_PLL208_UNLOCK_SC (0x0002) +#define U300_SYSCON_PICLR_PLL208_LOCK_SC (0x0001) +/* CAMIF_CONTROL 16 bit (-/W) */ +#define U300_SYSCON_CICR (0x013C) +#define U300_SYSCON_CICR_MASK (0x0FFF) +#define U300_SYSCON_CICR_APP_SUBLVDS_TESTMODE_MASK (0x0F00) +#define U300_SYSCON_CICR_APP_SUBLVDS_TESTMODE_PORT1 (0x0C00) +#define U300_SYSCON_CICR_APP_SUBLVDS_TESTMODE_PORT0 (0x0300) +#define U300_SYSCON_CICR_APP_SUBLVDS_RESCON_MASK (0x00F0) +#define U300_SYSCON_CICR_APP_SUBLVDS_RESCON_PORT1 (0x00C0) +#define U300_SYSCON_CICR_APP_SUBLVDS_RESCON_PORT0 (0x0030) +#define U300_SYSCON_CICR_APP_SUBLVDS_PWR_DWN_N_MASK (0x000F) +#define U300_SYSCON_CICR_APP_SUBLVDS_PWR_DWN_N_PORT1 (0x000C) +#define U300_SYSCON_CICR_APP_SUBLVDS_PWR_DWN_N_PORT0 (0x0003) /* Clock activity observability register 0 */ #define U300_SYSCON_C0OAR (0x140) #define U300_SYSCON_C0OAR_MASK (0xFFFF) @@ -513,7 +608,7 @@ /** * CPU medium frequency in MHz */ -#define SYSCON_CPU_CLOCK_MEDIUM 104 +#define SYSCON_CPU_CLOCK_MEDIUM 52 /** * CPU low frequency in MHz */ @@ -527,7 +622,7 @@ /** * EMIF medium frequency in MHz */ -#define SYSCON_EMIF_CLOCK_MEDIUM 104 +#define SYSCON_EMIF_CLOCK_MEDIUM 52 /** * EMIF low frequency in MHz */ @@ -541,7 +636,7 @@ /** * AHB medium frequency in MHz */ -#define SYSCON_AHB_CLOCK_MEDIUM 52 +#define SYSCON_AHB_CLOCK_MEDIUM 26 /** * AHB low frequency in MHz */ @@ -553,6 +648,15 @@ enum syscon_busmaster { SYSCON_BM_VIDEO_ENC }; +/* Selectr a resistor or a set of resistors */ +enum syscon_pull_up_down { + SYSCON_PU_KEY_IN_EN, + SYSCON_PU_EMIF_1_8_BIT_EN, + SYSCON_PU_EMIF_1_16_BIT_EN, + SYSCON_PU_EMIF_1_NFIF_READY_EN, + SYSCON_PU_EMIF_1_NFIF_WAIT_N_EN, +}; + /* * Note that this array must match the order of the array "clk_reg" * in syscon.c @@ -575,6 +679,7 @@ enum syscon_clk { SYSCON_CLKCONTROL_SPI, SYSCON_CLKCONTROL_I2S0_CORE, SYSCON_CLKCONTROL_I2S1_CORE, + SYSCON_CLKCONTROL_UART1, SYSCON_CLKCONTROL_AAIF, SYSCON_CLKCONTROL_AHB, SYSCON_CLKCONTROL_APEX, @@ -604,7 +709,8 @@ enum syscon_sysclk_mode { enum syscon_sysclk_req { SYSCON_SYSCLKREQ_DISABLED, - SYSCON_SYSCLKREQ_ACTIVE_LOW + SYSCON_SYSCLKREQ_ACTIVE_LOW, + SYSCON_SYSCLKREQ_MONITOR }; enum syscon_clk_mode { -- cgit v1.2.3-70-g09d2 From df1e0520f9434b5b771c854a13dd928727d8673a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 10 Aug 2009 12:52:40 +0100 Subject: ARM: 5666/1: Revamped U300 padmux API This abstracts the hackish padmux API on the U300 platform into something more manageable. It provides a way for drivers to activate/deactivate a certain padmux setting. It will also switch the users of the old API over to using the new style, pushing muxing into the apropriate setup files. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/gpio.c | 13 -- arch/arm/mach-u300/mmc.c | 16 ++ arch/arm/mach-u300/padmux.c | 395 +++++++++++++++++++++++++++++++++++++++----- arch/arm/mach-u300/padmux.h | 28 +++- 4 files changed, 392 insertions(+), 60 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c index 308cdb197a9..63c8f27fb15 100644 --- a/arch/arm/mach-u300/gpio.c +++ b/arch/arm/mach-u300/gpio.c @@ -25,11 +25,6 @@ #include #include -/* Need access to SYSCON registers for PADmuxing */ -#include - -#include "padmux.h" - /* Reference to GPIO block clock */ static struct clk *clk; @@ -606,14 +601,6 @@ static int __init gpio_probe(struct platform_device *pdev) writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); #endif - /* Set up some padmuxing here */ -#ifdef CONFIG_MMC - pmx_set_mission_mode_mmc(); -#endif -#ifdef CONFIG_SPI_PL022 - pmx_set_mission_mode_spi(); -#endif - gpio_set_initial_values(); for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c index 3138d3955c9..e66284d7356 100644 --- a/arch/arm/mach-u300/mmc.c +++ b/arch/arm/mach-u300/mmc.c @@ -22,6 +22,7 @@ #include #include "mmc.h" +#include "padmux.h" struct mmci_card_event { struct input_dev *mmc_input; @@ -146,6 +147,7 @@ int __devinit mmc_init(struct amba_device *adev) { struct mmci_card_event *mmci_card; struct device *mmcsd_device = &adev->dev; + struct pmx *pmx; int ret = 0; mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL); @@ -205,6 +207,20 @@ int __devinit mmc_init(struct amba_device *adev) input_set_drvdata(mmci_card->mmc_input, mmci_card); + /* + * Setup padmuxing for MMC. Since this must always be + * compiled into the kernel, pmx is never released. + */ + pmx = pmx_get(mmcsd_device, U300_APP_PMX_MMC_SETTING); + + if (IS_ERR(pmx)) + pr_warning("Could not get padmux handle\n"); + else { + ret = pmx_activate(mmcsd_device, pmx); + if (IS_ERR_VALUE(ret)) + pr_warning("Could not activate padmuxing\n"); + } + ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback, mmci_card); diff --git a/arch/arm/mach-u300/padmux.c b/arch/arm/mach-u300/padmux.c index f3664564f08..4c93c6cefd3 100644 --- a/arch/arm/mach-u300/padmux.c +++ b/arch/arm/mach-u300/padmux.c @@ -6,53 +6,362 @@ * Copyright (C) 2009 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 * U300 PADMUX functions - * Author: Linus Walleij - * + * Author: Martin Persson */ -#include + +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include - #include "padmux.h" -/* Set the PAD MUX to route the MMC reader correctly to GPIO0. */ -void pmx_set_mission_mode_mmc(void) -{ - u16 val; - - val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1LR); - val &= ~U300_SYSCON_PMC1LR_MMCSD_MASK; - writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1LR); - val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR); - val &= ~U300_SYSCON_PMC1HR_APP_GPIO_1_MASK; - val |= U300_SYSCON_PMC1HR_APP_GPIO_1_MMC; - writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR); -} - -void pmx_set_mission_mode_spi(void) -{ - u16 val; - - /* Set up padmuxing so the SPI port and its chipselects are active */ - val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR); - /* - * Activate the SPI port (disable the use of these pins for generic - * GPIO, DSP, AAIF - */ - val &= ~U300_SYSCON_PMC1HR_APP_SPI_2_MASK; - val |= U300_SYSCON_PMC1HR_APP_SPI_2_SPI; - /* - * Use GPIO pin SPI CS1 for CS1 actually (it can be used for other - * things also) - */ - val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK; - val |= U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI; - /* - * Use GPIO pin SPI CS2 for CS2 actually (it can be used for other - * things also) - */ - val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK; - val |= U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI; - writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR); +static DEFINE_MUTEX(pmx_mutex); + +const u32 pmx_registers[] = { + (U300_SYSCON_VBASE + U300_SYSCON_PMC1LR), + (U300_SYSCON_VBASE + U300_SYSCON_PMC1HR), + (U300_SYSCON_VBASE + U300_SYSCON_PMC2R), + (U300_SYSCON_VBASE + U300_SYSCON_PMC3R), + (U300_SYSCON_VBASE + U300_SYSCON_PMC4R) +}; + +/* High level functionality */ + +/* Lazy dog: + * onmask = { + * {"PMC1LR" mask, "PMC1LR" value}, + * {"PMC1HR" mask, "PMC1HR" value}, + * {"PMC2R" mask, "PMC2R" value}, + * {"PMC3R" mask, "PMC3R" value}, + * {"PMC4R" mask, "PMC4R" value} + * } + */ +static struct pmx mmc_setting = { + .setting = U300_APP_PMX_MMC_SETTING, + .default_on = false, + .activated = false, + .name = "MMC", + .onmask = { + {U300_SYSCON_PMC1LR_MMCSD_MASK, + U300_SYSCON_PMC1LR_MMCSD_MMCSD}, + {0, 0}, + {0, 0}, + {0, 0}, + {U300_SYSCON_PMC4R_APP_MISC_12_MASK, + U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO} + }, +}; + +static struct pmx spi_setting = { + .setting = U300_APP_PMX_SPI_SETTING, + .default_on = false, + .activated = false, + .name = "SPI", + .onmask = {{0, 0}, + {U300_SYSCON_PMC1HR_APP_SPI_2_MASK | + U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK | + U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK, + U300_SYSCON_PMC1HR_APP_SPI_2_SPI | + U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI | + U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI}, + {0, 0}, + {0, 0}, + {0, 0} + }, +}; + +/* Available padmux settings */ +static struct pmx *pmx_settings[] = { + &mmc_setting, + &spi_setting, +}; + +static void update_registers(struct pmx *pmx, bool activate) +{ + u16 regval, val, mask; + int i; + + for (i = 0; i < ARRAY_SIZE(pmx_registers); i++) { + if (activate) + val = pmx->onmask[i].val; + else + val = 0; + + mask = pmx->onmask[i].mask; + if (mask != 0) { + regval = readw(pmx_registers[i]); + regval &= ~mask; + regval |= val; + writew(regval, pmx_registers[i]); + } + } +} + +struct pmx *pmx_get(struct device *dev, enum pmx_settings setting) +{ + int i; + struct pmx *pmx = ERR_PTR(-ENOENT); + + if (dev == NULL) + return ERR_PTR(-EINVAL); + + mutex_lock(&pmx_mutex); + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + + if (setting == pmx_settings[i]->setting) { + + if (pmx_settings[i]->dev != NULL) { + WARN(1, "padmux: required setting " + "in use by another consumer\n"); + } else { + pmx = pmx_settings[i]; + pmx->dev = dev; + dev_dbg(dev, "padmux: setting nr %d is now " + "bound to %s and ready to use\n", + setting, dev_name(dev)); + break; + } + } + } + mutex_unlock(&pmx_mutex); + + return pmx; +} +EXPORT_SYMBOL(pmx_get); + +int pmx_put(struct device *dev, struct pmx *pmx) +{ + int i; + int ret = -ENOENT; + + if (pmx == NULL || dev == NULL) + return -EINVAL; + + mutex_lock(&pmx_mutex); + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + + if (pmx->setting == pmx_settings[i]->setting) { + + if (dev != pmx->dev) { + WARN(1, "padmux: cannot release handle as " + "it is bound to another consumer\n"); + ret = -EINVAL; + break; + } else { + pmx_settings[i]->dev = NULL; + ret = 0; + break; + } + } + } + mutex_unlock(&pmx_mutex); + + return ret; +} +EXPORT_SYMBOL(pmx_put); + +int pmx_activate(struct device *dev, struct pmx *pmx) +{ + int i, j, ret; + ret = 0; + + if (pmx == NULL || dev == NULL) + return -EINVAL; + + mutex_lock(&pmx_mutex); + + /* Make sure the required bits are not used */ + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + + if (pmx_settings[i]->dev == NULL || pmx_settings[i] == pmx) + continue; + + for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) { + + if (pmx_settings[i]->onmask[j].mask & pmx-> + onmask[j].mask) { + /* More than one entry on the same bits */ + WARN(1, "padmux: cannot activate " + "setting. Bit conflict with " + "an active setting\n"); + + ret = -EUSERS; + goto exit; + } + } + } + update_registers(pmx, true); + pmx->activated = true; + dev_dbg(dev, "padmux: setting nr %d is activated\n", + pmx->setting); + +exit: + mutex_unlock(&pmx_mutex); + return ret; +} +EXPORT_SYMBOL(pmx_activate); + +int pmx_deactivate(struct device *dev, struct pmx *pmx) +{ + int i; + int ret = -ENOENT; + + if (pmx == NULL || dev == NULL) + return -EINVAL; + + mutex_lock(&pmx_mutex); + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + + if (pmx_settings[i]->dev == NULL) + continue; + + if (pmx->setting == pmx_settings[i]->setting) { + + if (dev != pmx->dev) { + WARN(1, "padmux: cannot deactivate " + "pmx setting as it was activated " + "by another consumer\n"); + + ret = -EBUSY; + continue; + } else { + update_registers(pmx, false); + pmx_settings[i]->dev = NULL; + pmx->activated = false; + ret = 0; + dev_dbg(dev, "padmux: setting nr %d is deactivated", + pmx->setting); + break; + } + } + } + mutex_unlock(&pmx_mutex); + + return ret; +} +EXPORT_SYMBOL(pmx_deactivate); + +/* + * For internal use only. If it is to be exported, + * it should be reentrant. Notice that pmx_activate + * (i.e. runtime settings) always override default settings. + */ +static int pmx_set_default(void) +{ + /* Used to identify several entries on the same bits */ + u16 modbits[ARRAY_SIZE(pmx_registers)]; + + int i, j; + + memset(modbits, 0, ARRAY_SIZE(pmx_registers) * sizeof(u16)); + + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + + if (!pmx_settings[i]->default_on) + continue; + + for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) { + + /* Make sure there is only one entry on the same bits */ + if (modbits[j] & pmx_settings[i]->onmask[j].mask) { + BUG(); + return -EUSERS; + } + modbits[j] |= pmx_settings[i]->onmask[j].mask; + } + update_registers(pmx_settings[i], true); + } + return 0; } + +#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG)) +static int pmx_show(struct seq_file *s, void *data) +{ + int i; + seq_printf(s, "-------------------------------------------------\n"); + seq_printf(s, "SETTING BOUND TO DEVICE STATE\n"); + seq_printf(s, "-------------------------------------------------\n"); + mutex_lock(&pmx_mutex); + for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) { + /* Format pmx and device name nicely */ + char cdp[33]; + int chars; + + chars = snprintf(&cdp[0], 17, "%s", pmx_settings[i]->name); + while (chars < 16) { + cdp[chars] = ' '; + chars++; + } + chars = snprintf(&cdp[16], 17, "%s", pmx_settings[i]->dev ? + dev_name(pmx_settings[i]->dev) : "N/A"); + while (chars < 16) { + cdp[chars+16] = ' '; + chars++; + } + cdp[32] = '\0'; + + seq_printf(s, + "%s\t%s\n", + &cdp[0], + pmx_settings[i]->activated ? + "ACTIVATED" : "DEACTIVATED" + ); + + } + mutex_unlock(&pmx_mutex); + return 0; +} + +static int pmx_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmx_show, NULL); +} + +static const struct file_operations pmx_operations = { + .owner = THIS_MODULE, + .open = pmx_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init init_pmx_read_debugfs(void) +{ + /* Expose a simple debugfs interface to view pmx settings */ + (void) debugfs_create_file("padmux", S_IFREG | S_IRUGO, + NULL, NULL, + &pmx_operations); + return 0; +} + +/* + * This needs to come in after the core_initcall(), + * because debugfs is not available until + * the subsystems come up. + */ +module_init(init_pmx_read_debugfs); +#endif + +static int __init pmx_init(void) +{ + int ret; + + ret = pmx_set_default(); + + if (IS_ERR_VALUE(ret)) + pr_crit("padmux: default settings could not be set\n"); + + return 0; +} + +/* Should be initialized before consumers */ +core_initcall(pmx_init); diff --git a/arch/arm/mach-u300/padmux.h b/arch/arm/mach-u300/padmux.h index 8c2099ac504..6e8b8606409 100644 --- a/arch/arm/mach-u300/padmux.h +++ b/arch/arm/mach-u300/padmux.h @@ -6,14 +6,34 @@ * Copyright (C) 2009 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 * U300 PADMUX API - * Author: Linus Walleij - * + * Author: Martin Persson */ #ifndef __MACH_U300_PADMUX_H #define __MACH_U300_PADMUX_H -void pmx_set_mission_mode_mmc(void); -void pmx_set_mission_mode_spi(void); +enum pmx_settings { + U300_APP_PMX_MMC_SETTING, + U300_APP_PMX_SPI_SETTING +}; + +struct pmx_onmask { + u16 mask; /* Mask bits */ + u16 val; /* Value when active */ +}; + +struct pmx { + struct device *dev; + enum pmx_settings setting; + char *name; + bool activated; + bool default_on; + struct pmx_onmask onmask[]; +}; + +struct pmx *pmx_get(struct device *dev, enum pmx_settings setting); +int pmx_put(struct device *dev, struct pmx *pmx); +int pmx_activate(struct device *dev, struct pmx *pmx); +int pmx_deactivate(struct device *dev, struct pmx *pmx); #endif -- cgit v1.2.3-70-g09d2 From c7c8c78fdf6e9bd65d8ee879115dc2cd5d9fd0dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Aug 2009 10:59:05 +0100 Subject: ARM: 5667/3: U300 SSP/SPI board setup and test This adds a U300 board configuration for the PL022 SSP/SPI PrimeCell driver recently merged to the 2.6.31-rc series. Further it adds a dummy loopback SPI chip that can be used for testing the SPI functionality on a running system using the loopback mode of PL022. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/Kconfig | 12 ++ arch/arm/mach-u300/Makefile | 2 + arch/arm/mach-u300/core.c | 6 + arch/arm/mach-u300/dummyspichip.c | 290 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-u300/spi.c | 124 ++++++++++++++++ arch/arm/mach-u300/spi.h | 26 ++++ 6 files changed, 460 insertions(+) create mode 100644 arch/arm/mach-u300/dummyspichip.c create mode 100644 arch/arm/mach-u300/spi.c create mode 100644 arch/arm/mach-u300/spi.h (limited to 'arch') diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index 337b9aabce4..801b21e7f67 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -81,6 +81,18 @@ config MACH_U300_SEMI_IS_SHARED Memory Interface) from both from access and application side. +config MACH_U300_SPIDUMMY + bool "SSP/SPI dummy chip" + select SPI + select SPI_MASTER + select SPI_PL022 + help + This creates a small kernel module that creates a dummy + SPI device to be used for loopback tests. Regularly used + to test reference designs. If you're not testing SPI, + you don't need it. Selecting this will activate the + SPI framework and ARM PL022 support. + comment "All the settings below must match the bootloader's settings" config MACH_U300_ACCESS_MEM_SIZE diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile index 24950e0df4b..4941f89ea79 100644 --- a/arch/arm/mach-u300/Makefile +++ b/arch/arm/mach-u300/Makefile @@ -9,3 +9,5 @@ obj- := obj-$(CONFIG_ARCH_U300) += u300.o obj-$(CONFIG_MMC) += mmc.o +obj-$(CONFIG_SPI_PL022) += spi.o +obj-$(CONFIG_MACH_U300_SPIDUMMY) += dummyspichip.o diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 89b3ccf35e1..38d08a1c25d 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -32,6 +32,7 @@ #include "clock.h" #include "mmc.h" +#include "spi.h" /* * Static I/O mappings that are needed for booting the U300 platforms. The @@ -611,6 +612,8 @@ void __init u300_init_devices(void) /* Wait for the PLL208 to lock if not locked in yet */ while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) & U300_SYSCON_CSR_PLL208_LOCK_IND)); + /* Initialize SPI device with some board specifics */ + u300_spi_init(&pl022_device); /* Register the AMBA devices in the AMBA bus abstraction layer */ u300_clock_primecells(); @@ -622,6 +625,9 @@ void __init u300_init_devices(void) u300_assign_physmem(); + /* Register subdevices on the SPI bus */ + u300_spi_register_board_devices(); + /* Register the platform devices */ platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c new file mode 100644 index 00000000000..962f9de454d --- /dev/null +++ b/arch/arm/mach-u300/dummyspichip.c @@ -0,0 +1,290 @@ +/* + * arch/arm/mach-u300/dummyspichip.c + * + * Copyright (C) 2007-2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * This is a dummy loopback SPI "chip" used for testing SPI. + * Author: Linus Walleij + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * WARNING! Do not include this pl022-specific controller header + * for any generic driver. It is only done in this dummy chip + * because we alter the chip configuration in order to test some + * different settings on the loopback device. Normal chip configs + * shall be STATIC and not altered by the driver! + */ +#include + +struct dummy { + struct device *dev; + struct mutex lock; +}; + +#define DMA_TEST_SIZE 2048 + +/* When we cat /sys/bus/spi/devices/spi0.0/looptest this will be triggered */ +static ssize_t dummy_looptest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct dummy *p_dummy = dev_get_drvdata(&spi->dev); + + /* + * WARNING! Do not dereference the chip-specific data in any normal + * driver for a chip. It is usually STATIC and shall not be read + * or written to. Your chip driver should NOT depend on fields in this + * struct, this is just used here to alter the behaviour of the chip + * in order to perform tests. + */ + struct pl022_config_chip *chip_info = spi->controller_data; + int status; + u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD, + 0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05, + 0xF0, 0x0D}; + u8 rxbuf[14]; + u8 *bigtxbuf_virtual; + u8 *bigrxbuf_virtual; + + if (mutex_lock_interruptible(&p_dummy->lock)) + return -ERESTARTSYS; + + bigtxbuf_virtual = kmalloc(DMA_TEST_SIZE, GFP_KERNEL); + if (bigtxbuf_virtual == NULL) { + status = -ENOMEM; + goto out; + } + bigrxbuf_virtual = kmalloc(DMA_TEST_SIZE, GFP_KERNEL); + + /* Fill TXBUF with some happy pattern */ + memset(bigtxbuf_virtual, 0xAA, DMA_TEST_SIZE); + + /* + * Force chip to 8 bit mode + * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC! + */ + chip_info->data_size = SSP_DATA_BITS_8; + /* You should NOT DO THIS EITHER */ + spi->master->setup(spi); + + /* Now run the tests for 8bit mode */ + pr_info("Simple test 1: write 0xAA byte, read back garbage byte " + "in 8bit mode\n"); + status = spi_w8r8(spi, 0xAA); + if (status < 0) + pr_warning("Siple test 1: FAILURE: spi_write_then_read " + "failed with status %d\n", status); + else + pr_info("Simple test 1: SUCCESS!\n"); + + pr_info("Simple test 2: write 8 bytes, read back 8 bytes garbage " + "in 8bit mode (full FIFO)\n"); + status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); + if (status < 0) + pr_warning("Simple test 2: FAILURE: spi_write_then_read() " + "failed with status %d\n", status); + else + pr_info("Simple test 2: SUCCESS!\n"); + + pr_info("Simple test 3: write 14 bytes, read back 14 bytes garbage " + "in 8bit mode (see if we overflow FIFO)\n"); + status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); + if (status < 0) + pr_warning("Simple test 3: FAILURE: failed with status %d " + "(probably FIFO overrun)\n", status); + else + pr_info("Simple test 3: SUCCESS!\n"); + + pr_info("Simple test 4: write 8 bytes with spi_write(), read 8 " + "bytes garbage with spi_read() in 8bit mode\n"); + status = spi_write(spi, &txbuf[0], 8); + if (status < 0) + pr_warning("Simple test 4 step 1: FAILURE: spi_write() " + "failed with status %d\n", status); + else + pr_info("Simple test 4 step 1: SUCCESS!\n"); + status = spi_read(spi, &rxbuf[0], 8); + if (status < 0) + pr_warning("Simple test 4 step 2: FAILURE: spi_read() " + "failed with status %d\n", status); + else + pr_info("Simple test 4 step 2: SUCCESS!\n"); + + pr_info("Simple test 5: write 14 bytes with spi_write(), read " + "14 bytes garbage with spi_read() in 8bit mode\n"); + status = spi_write(spi, &txbuf[0], 14); + if (status < 0) + pr_warning("Simple test 5 step 1: FAILURE: spi_write() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 5 step 1: SUCCESS!\n"); + status = spi_read(spi, &rxbuf[0], 14); + if (status < 0) + pr_warning("Simple test 5 step 2: FAILURE: spi_read() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 5: SUCCESS!\n"); + + pr_info("Simple test 6: write %d bytes with spi_write(), " + "read %d bytes garbage with spi_read() in 8bit mode\n", + DMA_TEST_SIZE, DMA_TEST_SIZE); + status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); + if (status < 0) + pr_warning("Simple test 6 step 1: FAILURE: spi_write() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 6 step 1: SUCCESS!\n"); + status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); + if (status < 0) + pr_warning("Simple test 6 step 2: FAILURE: spi_read() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 6: SUCCESS!\n"); + + + /* + * Force chip to 16 bit mode + * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC! + */ + chip_info->data_size = SSP_DATA_BITS_16; + /* You should NOT DO THIS EITHER */ + spi->master->setup(spi); + + pr_info("Simple test 7: write 0xAA byte, read back garbage byte " + "in 16bit bus mode\n"); + status = spi_w8r8(spi, 0xAA); + if (status == -EIO) + pr_info("Simple test 7: SUCCESS! (expected failure with " + "status EIO)\n"); + else if (status < 0) + pr_warning("Siple test 7: FAILURE: spi_write_then_read " + "failed with status %d\n", status); + else + pr_warning("Siple test 7: FAILURE: spi_write_then_read " + "succeeded but it was expected to fail!\n"); + + pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage " + "in 16bit mode (full FIFO)\n"); + status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); + if (status < 0) + pr_warning("Simple test 8: FAILURE: spi_write_then_read() " + "failed with status %d\n", status); + else + pr_info("Simple test 8: SUCCESS!\n"); + + pr_info("Simple test 9: write 14 bytes, read back 14 bytes garbage " + "in 16bit mode (see if we overflow FIFO)\n"); + status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); + if (status < 0) + pr_warning("Simple test 9: FAILURE: failed with status %d " + "(probably FIFO overrun)\n", status); + else + pr_info("Simple test 9: SUCCESS!\n"); + + pr_info("Simple test 10: write %d bytes with spi_write(), " + "read %d bytes garbage with spi_read() in 16bit mode\n", + DMA_TEST_SIZE, DMA_TEST_SIZE); + status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); + if (status < 0) + pr_warning("Simple test 10 step 1: FAILURE: spi_write() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 10 step 1: SUCCESS!\n"); + + status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); + if (status < 0) + pr_warning("Simple test 10 step 2: FAILURE: spi_read() " + "failed with status %d (probably FIFO overrun)\n", + status); + else + pr_info("Simple test 10: SUCCESS!\n"); + + status = sprintf(buf, "loop test complete\n"); + kfree(bigrxbuf_virtual); + kfree(bigtxbuf_virtual); + out: + mutex_unlock(&p_dummy->lock); + return status; +} + +static DEVICE_ATTR(looptest, S_IRUGO, dummy_looptest, NULL); + +static int __devinit pl022_dummy_probe(struct spi_device *spi) +{ + struct dummy *p_dummy; + int status; + + dev_info(&spi->dev, "probing dummy SPI device\n"); + + p_dummy = kzalloc(sizeof *p_dummy, GFP_KERNEL); + if (!p_dummy) + return -ENOMEM; + + dev_set_drvdata(&spi->dev, p_dummy); + mutex_init(&p_dummy->lock); + + /* sysfs hook */ + status = device_create_file(&spi->dev, &dev_attr_looptest); + if (status) { + dev_dbg(&spi->dev, "device_create_file looptest failure.\n"); + goto out_dev_create_looptest_failed; + } + + return 0; + +out_dev_create_looptest_failed: + dev_set_drvdata(&spi->dev, NULL); + kfree(p_dummy); + return status; +} + +static int __devexit pl022_dummy_remove(struct spi_device *spi) +{ + struct dummy *p_dummy = dev_get_drvdata(&spi->dev); + + dev_info(&spi->dev, "removing dummy SPI device\n"); + device_remove_file(&spi->dev, &dev_attr_looptest); + dev_set_drvdata(&spi->dev, NULL); + kfree(p_dummy); + + return 0; +} + +static struct spi_driver pl022_dummy_driver = { + .driver = { + .name = "spi-dummy", + .owner = THIS_MODULE, + }, + .probe = pl022_dummy_probe, + .remove = __devexit_p(pl022_dummy_remove), +}; + +static int __init pl022_init_dummy(void) +{ + return spi_register_driver(&pl022_dummy_driver); +} + +static void __exit pl022_exit_dummy(void) +{ + spi_unregister_driver(&pl022_dummy_driver); +} + +module_init(pl022_init_dummy); +module_exit(pl022_exit_dummy); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("PL022 SSP/SPI DUMMY Linux driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c new file mode 100644 index 00000000000..307d007ea7f --- /dev/null +++ b/arch/arm/mach-u300/spi.c @@ -0,0 +1,124 @@ +/* + * arch/arm/mach-u300/spi.c + * + * Copyright (C) 2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * + * Author: Linus Walleij + */ +#include +#include +#include +#include +#include +#include "padmux.h" + +/* + * The following is for the actual devices on the SSP/SPI bus + */ +#ifdef CONFIG_MACH_U300_SPIDUMMY +static void select_dummy_chip(u32 chipselect) +{ + pr_debug("CORE: %s called with CS=0x%x (%s)\n", + __func__, + chipselect, + chipselect ? "unselect chip" : "select chip"); + /* + * Here you would write the chip select value to the GPIO pins if + * this was a real chip (but this is a loopback dummy). + */ +} + +struct pl022_config_chip dummy_chip_info = { + /* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */ + .lbm = LOOPBACK_ENABLED, + /* + * available POLLING_TRANSFER and INTERRUPT_TRANSFER, + * DMA_TRANSFER does not work + */ + .com_mode = INTERRUPT_TRANSFER, + .iface = SSP_INTERFACE_MOTOROLA_SPI, + /* We can only act as master but SSP_SLAVE is possible in theory */ + .hierarchy = SSP_MASTER, + /* 0 = drive TX even as slave, 1 = do not drive TX as slave */ + .slave_tx_disable = 0, + /* LSB first */ + .endian_tx = SSP_TX_LSB, + .endian_rx = SSP_RX_LSB, + .data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */ + .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, + .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, + .clk_phase = SSP_CLK_FALLING_EDGE, + .clk_pol = SSP_CLK_POL_IDLE_LOW, + .ctrl_len = SSP_BITS_12, + .wait_state = SSP_MWIRE_WAIT_ZERO, + .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, + /* + * This is where you insert a call to a function to enable CS + * (usually GPIO) for a certain chip. + */ + .cs_control = select_dummy_chip, +}; +#endif + +static struct spi_board_info u300_spi_devices[] = { +#ifdef CONFIG_MACH_U300_SPIDUMMY + { + /* A dummy chip used for loopback tests */ + .modalias = "spi-dummy", + /* Really dummy, pass in additional chip config here */ + .platform_data = NULL, + /* This defines how the controller shall handle the device */ + .controller_data = &dummy_chip_info, + /* .irq - no external IRQ routed from this device */ + .max_speed_hz = 1000000, + .bus_num = 0, /* Only one bus on this chip */ + .chip_select = 0, + /* Means SPI_CS_HIGH, change if e.g low CS */ + .mode = 0, + }, +#endif +}; + +static struct pl022_ssp_controller ssp_platform_data = { + /* If you have several SPI buses this varies, we have only bus 0 */ + .bus_id = 0, + /* Set this to 1 when we think we got DMA working */ + .enable_dma = 0, + /* + * On the APP CPU GPIO 4, 5 and 6 are connected as generic + * chip selects for SPI. (Same on U330, U335 and U365.) + * TODO: make sure the GPIO driver can select these properly + * and do padmuxing accordingly too. + */ + .num_chipselect = 3, +}; + + +void __init u300_spi_init(struct amba_device *adev) +{ + struct pmx *pmx; + + adev->dev.platform_data = &ssp_platform_data; + /* + * Setup padmuxing for SPI. Since this must always be + * compiled into the kernel, pmx is never released. + */ + pmx = pmx_get(&adev->dev, U300_APP_PMX_SPI_SETTING); + + if (IS_ERR(pmx)) + dev_warn(&adev->dev, "Could not get padmux handle\n"); + else { + int ret; + + ret = pmx_activate(&adev->dev, pmx); + if (IS_ERR_VALUE(ret)) + dev_warn(&adev->dev, "Could not activate padmuxing\n"); + } + +} +void __init u300_spi_register_board_devices(void) +{ + /* Register any SPI devices */ + spi_register_board_info(u300_spi_devices, ARRAY_SIZE(u300_spi_devices)); +} diff --git a/arch/arm/mach-u300/spi.h b/arch/arm/mach-u300/spi.h new file mode 100644 index 00000000000..bd3d867e240 --- /dev/null +++ b/arch/arm/mach-u300/spi.h @@ -0,0 +1,26 @@ +/* + * arch/arm/mach-u300/spi.h + * + * Copyright (C) 2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * + * Author: Linus Walleij + */ +#ifndef SPI_H +#define SPI_H +#include + +#ifdef CONFIG_SPI_PL022 +void __init u300_spi_init(struct amba_device *adev); +void __init u300_spi_register_board_devices(void); +#else +/* Compile out SPI support if PL022 is not selected */ +static inline void __init u300_spi_init(struct amba_device *adev) +{ +} +static inline void __init u300_spi_register_board_devices(void) +{ +} +#endif + +#endif -- cgit v1.2.3-70-g09d2 From 6be2a0cacc1ed6899a53172e2e9b7a3587be0bea Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 13 Aug 2009 21:42:01 +0100 Subject: ARM: 5668/2: U300 I2C board setup This sets up the U300 I2C subdevices so that the AB3100 analog baseband ASIC is properly detected and also the camera devices in the U335 reference design get properly registered. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/Makefile | 1 + arch/arm/mach-u300/core.c | 8 ++++++-- arch/arm/mach-u300/i2c.c | 43 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-u300/i2c.h | 23 +++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-u300/i2c.c create mode 100644 arch/arm/mach-u300/i2c.h (limited to 'arch') diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile index 4941f89ea79..885b5c027c1 100644 --- a/arch/arm/mach-u300/Makefile +++ b/arch/arm/mach-u300/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_ARCH_U300) += u300.o obj-$(CONFIG_MMC) += mmc.o obj-$(CONFIG_SPI_PL022) += spi.o obj-$(CONFIG_MACH_U300_SPIDUMMY) += dummyspichip.o +obj-$(CONFIG_I2C_STU300) += i2c.o diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 38d08a1c25d..bad1ba228cb 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -33,6 +33,7 @@ #include "clock.h" #include "mmc.h" #include "spi.h" +#include "i2c.h" /* * Static I/O mappings that are needed for booting the U300 platforms. The @@ -379,14 +380,14 @@ static struct platform_device wdog_device = { }; static struct platform_device i2c0_device = { - .name = "stddci2c", + .name = "stu300", .id = 0, .num_resources = ARRAY_SIZE(i2c0_resources), .resource = i2c0_resources, }; static struct platform_device i2c1_device = { - .name = "stddci2c", + .name = "stu300", .id = 1, .num_resources = ARRAY_SIZE(i2c1_resources), .resource = i2c1_resources, @@ -625,6 +626,9 @@ void __init u300_init_devices(void) u300_assign_physmem(); + /* Register subdevices on the I2C buses */ + u300_i2c_register_board_devices(); + /* Register subdevices on the SPI bus */ u300_spi_register_board_devices(); diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c new file mode 100644 index 00000000000..10be1f888b2 --- /dev/null +++ b/arch/arm/mach-u300/i2c.c @@ -0,0 +1,43 @@ +/* + * arch/arm/mach-u300/i2c.c + * + * Copyright (C) 2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * + * Register board i2c devices + * Author: Linus Walleij + */ +#include +#include +#include + +static struct i2c_board_info __initdata bus0_i2c_board_info[] = { + { + .type = "ab3100", + .addr = 0x48, + .irq = IRQ_U300_IRQ0_EXT, + }, +}; + +static struct i2c_board_info __initdata bus1_i2c_board_info[] = { +#ifdef CONFIG_MACH_U300_BS335 + { + .type = "fwcam", + .addr = 0x10, + }, + { + .type = "fwcam", + .addr = 0x5d, + }, +#else + { }, +#endif +}; + +void __init u300_i2c_register_board_devices(void) +{ + i2c_register_board_info(0, bus0_i2c_board_info, + ARRAY_SIZE(bus0_i2c_board_info)); + i2c_register_board_info(1, bus1_i2c_board_info, + ARRAY_SIZE(bus1_i2c_board_info)); +} diff --git a/arch/arm/mach-u300/i2c.h b/arch/arm/mach-u300/i2c.h new file mode 100644 index 00000000000..485c02e5c06 --- /dev/null +++ b/arch/arm/mach-u300/i2c.h @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-u300/i2c.h + * + * Copyright (C) 2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * + * Register board i2c devices + * Author: Linus Walleij + */ + +#ifndef MACH_U300_I2C_H +#define MACH_U300_I2C_H + +#ifdef CONFIG_I2C_STU300 +void __init u300_i2c_register_board_devices(void); +#else +/* Compile out this stuff if no I2C adapter is available */ +static inline void __init u300_i2c_register_board_devices(void) +{ +} +#endif + +#endif -- cgit v1.2.3-70-g09d2 From a2ca00ea9398265a26eabb358bba83c8b75c463d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Sep 2009 13:10:50 +0100 Subject: ARM: 5704/1: U300 sched_clock implementation v2 This adds the long debated sched_clock() override for the weak in-kernel jiffybased sched_clock(). The implementation is more or less identical to the one used in arch/arm/plat-omap/common.c and at last attempt to merge this the merge was postponed at the request of Peter Zijlstra due to pending discussions regarding generalized clocksource-based sched_clock() implementations by adding a flag to the clocksource. However that discussion ended up with the generic code needing to be rewritten and Paul Mundt see no reason not to proceed with this for the time being as it can be easily converted once the generic code is in place. Cc: Peter Zijlstra Cc: Paul Mundt Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/timer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c index cce53204880..26d26f5100f 100644 --- a/arch/arm/mach-u300/timer.c +++ b/arch/arm/mach-u300/timer.c @@ -346,6 +346,21 @@ static struct clocksource clocksource_u300_1mhz = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +/* + * Override the global weak sched_clock symbol with this + * local implementation which uses the clocksource to get some + * better resolution when scheduling the kernel. We accept that + * this wraps around for now, since it is just a relative time + * stamp. (Inspired by OMAP implementation.) + */ +unsigned long long notrace sched_clock(void) +{ + return clocksource_cyc2ns(clocksource_u300_1mhz.read( + &clocksource_u300_1mhz), + clocksource_u300_1mhz.mult, + clocksource_u300_1mhz.shift); +} + /* * This sets up the system timers, clock source and clock event. -- cgit v1.2.3-70-g09d2 From ee2b805c8eb6459cf541ef141ff70dae17af59ca Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 15 Aug 2009 15:12:05 +0100 Subject: ARM: 5678/1: SSP/SPI PL022 polarity terminology fix The definition of the SPI clock phase for the Motorola mode of the PL022 driver was incorrect: the spec had been interpreted as data being recieved on rising or falling edge of the clocks while the correct interpretation is that data can be recieved on the first or second edge transition, falling or rising depending on the polarity setting. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/spi.c | 2 +- drivers/spi/amba-pl022.c | 8 ++++---- include/linux/amba/pl022.h | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c index 307d007ea7f..f0e887bea30 100644 --- a/arch/arm/mach-u300/spi.c +++ b/arch/arm/mach-u300/spi.c @@ -48,7 +48,7 @@ struct pl022_config_chip dummy_chip_info = { .data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */ .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, - .clk_phase = SSP_CLK_FALLING_EDGE, + .clk_phase = SSP_CLK_SECOND_EDGE, .clk_pol = SSP_CLK_POL_IDLE_LOW, .ctrl_len = SSP_BITS_12, .wait_state = SSP_MWIRE_WAIT_ZERO, diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index da76797ce8b..35521af0d0d 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -534,7 +534,7 @@ static void restore_state(struct pl022 *pl022) GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \ GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \ GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ - GEN_MASK_BITS(SSP_CLK_FALLING_EDGE, SSP_CR0_MASK_SPH, 7) | \ + GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \ GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \ GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \ @@ -1249,8 +1249,8 @@ static int verify_controller_parameters(struct pl022 *pl022, return -EINVAL; } if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) { - if ((chip_info->clk_phase != SSP_CLK_RISING_EDGE) - && (chip_info->clk_phase != SSP_CLK_FALLING_EDGE)) { + if ((chip_info->clk_phase != SSP_CLK_FIRST_EDGE) + && (chip_info->clk_phase != SSP_CLK_SECOND_EDGE)) { dev_err(chip_info->dev, "Clock Phase is configured incorrectly\n"); return -EINVAL; @@ -1487,7 +1487,7 @@ static int pl022_setup(struct spi_device *spi) chip_info->data_size = SSP_DATA_BITS_12; chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM; chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC; - chip_info->clk_phase = SSP_CLK_FALLING_EDGE; + chip_info->clk_phase = SSP_CLK_SECOND_EDGE; chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW; chip_info->ctrl_len = SSP_BITS_8; chip_info->wait_state = SSP_MWIRE_WAIT_ZERO; diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h index dcad0ffd175..e4836c6b3dd 100644 --- a/include/linux/amba/pl022.h +++ b/include/linux/amba/pl022.h @@ -136,12 +136,12 @@ enum ssp_tx_level_trig { /** * enum SPI Clock Phase - clock phase (Motorola SPI interface only) - * @SSP_CLK_RISING_EDGE: Receive data on rising edge - * @SSP_CLK_FALLING_EDGE: Receive data on falling edge + * @SSP_CLK_FIRST_EDGE: Receive data on first edge transition (actual direction depends on polarity) + * @SSP_CLK_SECOND_EDGE: Receive data on second edge transition (actual direction depends on polarity) */ enum ssp_spi_clk_phase { - SSP_CLK_RISING_EDGE, - SSP_CLK_FALLING_EDGE + SSP_CLK_FIRST_EDGE, + SSP_CLK_SECOND_EDGE }; /** -- cgit v1.2.3-70-g09d2