diff options
Diffstat (limited to 'arch/arm/plat-samsung')
85 files changed, 11204 insertions, 0 deletions
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig new file mode 100644 index 00000000000..301b892d97d --- /dev/null +++ b/arch/arm/plat-samsung/Kconfig @@ -0,0 +1,494 @@ +# arch/arm/plat-samsung/Kconfig +# +# Copyright 2009 Simtec Electronics +# +# Licensed under GPLv2 + +config PLAT_SAMSUNG + bool + depends on PLAT_S3C24XX || ARCH_S3C64XX || PLAT_S5P || ARCH_EXYNOS + default y + select GENERIC_IRQ_CHIP + select NO_IOPORT_MAP + help + Base platform code for all Samsung SoC based systems + +config PLAT_S5P + bool + depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) + default y + select ARCH_REQUIRE_GPIOLIB + select ARM_VIC + select NO_IOPORT_MAP + select PLAT_SAMSUNG + select S3C_GPIO_TRACK + select S5P_GPIO_DRVSTR + select SAMSUNG_CLKSRC if !COMMON_CLK + help + Base platform code for Samsung's S5P series SoC. + +config SAMSUNG_PM + bool + depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || S5P_PM) + default y + help + Base platform power management code for samsung code + +if PLAT_SAMSUNG +menu "Samsung Common options" + +# boot configurations + +comment "Boot options" + +config S3C_LOWLEVEL_UART_PORT + int "S3C UART to use for low-level messages" + depends on ARCH_S3C64XX + default 0 + help + Choice of which UART port to use for the low-level messages, + such as the `Uncompressing...` at start time. The value of + this configuration should be between zero and two. The port + must have been initialised by the boot-loader before use. + +config SAMSUNG_ATAGS + def_bool n + depends on !ARCH_MULTIPLATFORM + depends on ATAGS + help + This option enables ATAGS based boot support code for + Samsung platforms, including static platform devices, legacy + clock, timer and interrupt initialization, etc. + + Platforms that support only DT based boot need not to select + this option. + +if SAMSUNG_ATAGS + +# clock options + +config SAMSUNG_CLOCK + bool + default y if !COMMON_CLK + +config SAMSUNG_CLKSRC + bool + help + Select the clock code for the clksrc implementation + used by newer systems such as the S3C64XX. + +config S5P_CLOCK + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) + help + Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs + +# options for IRQ support + +config S5P_IRQ + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) + help + Support common interrupt part for ARCH_S5P SoCs + +config S5P_EXT_INT + bool + help + Use the external interrupts (other than GPIO interrupts.) + Note: Do not choose this for S5P6440 and S5P6450. + +config S5P_GPIO_INT + bool + help + Common code for the GPIO interrupts (other than external interrupts.) + +# options for gpio configuration support + +config S5P_GPIO_DRVSTR + bool + help + Internal configuration to get and set correct GPIO driver strength + helper + +config SAMSUNG_GPIO_EXTRA + int "Number of additional GPIO pins" + default 128 if SAMSUNG_GPIO_EXTRA128 + default 64 if SAMSUNG_GPIO_EXTRA64 + default 0 + help + Use additional GPIO space in addition to the GPIO's the SOC + provides. This allows expanding the GPIO space for use with + GPIO expanders. + +config SAMSUNG_GPIO_EXTRA64 + bool + +config SAMSUNG_GPIO_EXTRA128 + bool + +config S3C_GPIO_SPACE + int "Space between gpio banks" + default 0 + help + Add a number of spare GPIO entries between each bank for debugging + purposes. This allows any problems where an counter overflows from + one bank to another to be caught, at the expense of using a little + more memory. + +config S3C_GPIO_TRACK + bool + help + Internal configuration option to enable the s3c specific gpio + chip tracking if the platform requires it. + +# uart options + +config S5P_DEV_UART + def_bool y + depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) + +# ADC driver + +config S3C_ADC + bool "ADC common driver support" + help + Core support for the ADC block found in the Samsung SoC systems + for drivers such as the touchscreen and hwmon to use to share + this resource. + +# device definitions to compile in + +config S3C_DEV_HSMMC + bool + help + Compile in platform device definitions for HSMMC code + +config S3C_DEV_HSMMC1 + bool + help + Compile in platform device definitions for HSMMC channel 1 + +config S3C_DEV_HSMMC2 + bool + help + Compile in platform device definitions for HSMMC channel 2 + +config S3C_DEV_HSMMC3 + bool + help + Compile in platform device definitions for HSMMC channel 3 + +config S3C_DEV_HWMON + bool + help + Compile in platform device definitions for HWMON + +config S3C_DEV_I2C1 + bool + help + Compile in platform device definitions for I2C channel 1 + +config S3C_DEV_I2C2 + bool + help + Compile in platform device definitions for I2C channel 2 + +config S3C_DEV_I2C3 + bool + help + Compile in platform device definition for I2C controller 3 + +config S3C_DEV_I2C4 + bool + help + Compile in platform device definition for I2C controller 4 + +config S3C_DEV_I2C5 + bool + help + Compile in platform device definition for I2C controller 5 + +config S3C_DEV_I2C6 + bool + help + Compile in platform device definition for I2C controller 6 + +config S3C_DEV_I2C7 + bool + help + Compile in platform device definition for I2C controller 7 + +config S3C_DEV_FB + bool + help + Compile in platform device definition for framebuffer + +config S3C_DEV_USB_HOST + bool + help + Compile in platform device definition for USB host. + +config S3C_DEV_USB_HSOTG + bool + help + Compile in platform device definition for USB high-speed OtG + +config S3C_DEV_WDT + bool + default y if ARCH_S3C24XX + help + Complie in platform device definition for Watchdog Timer + +config S3C_DEV_NAND + bool + help + Compile in platform device definition for NAND controller + +config S3C_DEV_ONENAND + bool + help + Compile in platform device definition for OneNAND controller + +config S3C_DEV_RTC + bool + help + Complie in platform device definition for RTC + +config SAMSUNG_DEV_ADC + bool + help + Compile in platform device definition for ADC controller + +config SAMSUNG_DEV_IDE + bool + help + Compile in platform device definitions for IDE + +config S3C64XX_DEV_SPI0 + bool + help + Compile in platform device definitions for S3C64XX's type + SPI controller 0 + +config S3C64XX_DEV_SPI1 + bool + help + Compile in platform device definitions for S3C64XX's type + SPI controller 1 + +config S3C64XX_DEV_SPI2 + bool + help + Compile in platform device definitions for S3C64XX's type + SPI controller 2 + +config SAMSUNG_DEV_TS + bool + help + Common in platform device definitions for touchscreen device + +config SAMSUNG_DEV_KEYPAD + bool + help + Compile in platform device definitions for keypad + +config SAMSUNG_DEV_PWM + bool + default y if ARCH_S3C24XX + help + Compile in platform device definition for PWM Timer + +config SAMSUNG_DEV_BACKLIGHT + bool + depends on SAMSUNG_DEV_PWM + help + Compile in platform device definition LCD backlight with PWM Timer + +config S5P_DEV_CSIS0 + bool + help + Compile in platform device definitions for MIPI-CSIS channel 0 + +config S5P_DEV_CSIS1 + bool + help + Compile in platform device definitions for MIPI-CSIS channel 1 + +config S5P_DEV_FIMC0 + bool + help + Compile in platform device definitions for FIMC controller 0 + +config S5P_DEV_FIMC1 + bool + help + Compile in platform device definitions for FIMC controller 1 + +config S5P_DEV_FIMC2 + bool + help + Compile in platform device definitions for FIMC controller 2 + +config S5P_DEV_FIMC3 + bool + help + Compile in platform device definitions for FIMC controller 3 + +config S5P_DEV_FIMD0 + bool + help + Compile in platform device definitions for FIMD controller 0 + +config S5P_DEV_G2D + bool + help + Compile in platform device definitions for G2D device + +config S5P_DEV_I2C_HDMIPHY + bool + help + Compile in platform device definitions for I2C HDMIPHY controller + +config S5P_DEV_JPEG + bool + help + Compile in platform device definitions for JPEG codec + +config S5P_DEV_ONENAND + bool + help + Compile in platform device definition for OneNAND controller + +config S5P_DEV_TV + bool + help + Compile in platform device definition for TV interface + +config S3C24XX_PWM + bool "PWM device support" + select PWM + select PWM_SAMSUNG + help + Support for exporting the PWM timer blocks via the pwm device + system + +config S3C_SETUP_CAMIF + bool + help + Compile in common setup code for S3C CAMIF devices + +# DMA + +config S3C_DMA + bool + help + Internal configuration for S3C DMA core + +config S5P_IRQ_PM + bool + default y if S5P_PM + help + Legacy IRQ power management for S5P platforms + +config SAMSUNG_PM_GPIO + bool + default y if GPIO_SAMSUNG && PM + help + Include legacy GPIO power management code for platforms not using + pinctrl-samsung driver. + +config SAMSUNG_DMADEV + bool "Use legacy Samsung DMA abstraction" + depends on CPU_S5PV210 || CPU_S5PC100 || ARCH_S5P64X0 || ARCH_S3C64XX + select DMADEVICES + default y + help + Use DMA device engine for PL330 DMAC. + +endif + +config S5P_DEV_MFC + bool + help + Compile in setup memory (init) code for MFC + +comment "Power management" + +config SAMSUNG_PM_DEBUG + bool "S3C2410 PM Suspend debug" + depends on PM && DEBUG_KERNEL && DEBUG_S3C_UART + help + Say Y here if you want verbose debugging from the PM Suspend and + Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> + for more information. + +config S3C_PM_DEBUG_LED_SMDK + bool "SMDK LED suspend/resume debugging" + depends on PM && (MACH_SMDK6410) + help + Say Y here to enable the use of the SMDK LEDs on the baseboard + for debugging of the state of the suspend and resume process. + + Note, this currently only works for S3C64XX based SMDK boards. + +config SAMSUNG_PM_CHECK + bool "S3C2410 PM Suspend Memory CRC" + depends on PM + select CRC32 + help + Enable the PM code's memory area checksum over sleep. This option + will generate CRCs of all blocks of memory, and store them before + going to sleep. The blocks are then checked on resume for any + errors. + + Note, this can take several seconds depending on memory size + and CPU speed. + + See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> + +config SAMSUNG_PM_CHECK_CHUNKSIZE + int "S3C2410 PM Suspend CRC Chunksize (KiB)" + depends on PM && SAMSUNG_PM_CHECK + default 64 + help + Set the chunksize in Kilobytes of the CRC for checking memory + corruption over suspend and resume. A smaller value will mean that + the CRC data block will take more memory, but wil identify any + faults with better precision. + + See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> + +config SAMSUNG_WAKEMASK + bool + depends on PM + help + Compile support for wakeup-mask controls found on the S3C6400 + and above. This code allows a set of interrupt to wakeup-mask + mappings. See <plat/wakeup-mask.h> + +config SAMSUNG_WDT_RESET + bool + help + Compile support for system restart by triggering watchdog reset. + Used on SoCs that do not provide dedicated reset control. + +config S5P_PM + bool + help + Common code for power management support on S5P and newer SoCs + Note: Do not select this for S5P6440 and S5P6450. + +config S5P_SLEEP + bool + help + Internal config node to apply common S5P sleep management code. + Can be selected by S5P and newer SoCs with similar sleep procedure. + +config DEBUG_S3C_UART + depends on PLAT_SAMSUNG + int + default "0" if DEBUG_S3C_UART0 + default "1" if DEBUG_S3C_UART1 + default "2" if DEBUG_S3C_UART2 + default "3" if DEBUG_S3C_UART3 + +endmenu +endif diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile new file mode 100644 index 00000000000..5e5beaa9ae1 --- /dev/null +++ b/arch/arm/plat-samsung/Makefile @@ -0,0 +1,64 @@ +# arch/arm/plat-samsung/Makefile +# +# Copyright 2009 Simtec Electronics +# +# Licensed under GPLv2 + +ccflags-$(CONFIG_ARCH_MULTI_V7) += -I$(srctree)/$(src)/include +ccflags-$(CONFIG_ARCH_EXYNOS) += -I$(srctree)/arch/arm/mach-exynos/include + +obj-y := +obj-m := +obj-n := dummy.o +obj- := + +# Objects we always build independent of SoC choice + +obj-y += init.o cpu.o + +obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o + +obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o +obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o + +obj-$(CONFIG_S5P_IRQ) += s5p-irq.o +obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o +obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o + +# ADC + +obj-$(CONFIG_S3C_ADC) += adc.o + +# devices + +obj-$(CONFIG_SAMSUNG_ATAGS) += platformdata.o + +obj-$(CONFIG_SAMSUNG_ATAGS) += devs.o +obj-$(CONFIG_SAMSUNG_ATAGS) += dev-uart.o +obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o +obj-$(CONFIG_S5P_DEV_UART) += s5p-dev-uart.o + +obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o + +obj-$(CONFIG_S3C_SETUP_CAMIF) += setup-camif.o + +# DMA support + +obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o + +obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o + +# PM support + +obj-$(CONFIG_PM_SLEEP) += pm-common.o +obj-$(CONFIG_SAMSUNG_PM) += pm.o +obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o +obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o +obj-$(CONFIG_SAMSUNG_PM_DEBUG) += pm-debug.o + +obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o +obj-$(CONFIG_SAMSUNG_WDT_RESET) += watchdog-reset.o + +obj-$(CONFIG_S5P_PM) += s5p-pm.o +obj-$(CONFIG_S5P_IRQ_PM) += s5p-irq-pm.o +obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c new file mode 100644 index 00000000000..79690f2f6d3 --- /dev/null +++ b/arch/arm/plat-samsung/adc.c @@ -0,0 +1,526 @@ +/* arch/arm/plat-samsung/adc.c + * + * Copyright (c) 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> + * + * Samsung ADC device core + * + * 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. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> + +#include <plat/regs-adc.h> +#include <plat/adc.h> + +/* This driver is designed to control the usage of the ADC block between + * the touchscreen and any other drivers that may need to use it, such as + * the hwmon driver. + * + * Priority will be given to the touchscreen driver, but as this itself is + * rate limited it should not starve other requests which are processed in + * order that they are received. + * + * Each user registers to get a client block which uniquely identifies it + * and stores information such as the necessary functions to callback when + * action is required. + */ + +enum s3c_cpu_type { + TYPE_ADCV1, /* S3C24XX */ + TYPE_ADCV11, /* S3C2443 */ + TYPE_ADCV12, /* S3C2416, S3C2450 */ + TYPE_ADCV2, /* S3C64XX, S5P64X0, S5PC100 */ + TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */ +}; + +struct s3c_adc_client { + struct platform_device *pdev; + struct list_head pend; + wait_queue_head_t *wait; + + unsigned int nr_samples; + int result; + unsigned char is_ts; + unsigned char channel; + + void (*select_cb)(struct s3c_adc_client *c, unsigned selected); + void (*convert_cb)(struct s3c_adc_client *c, + unsigned val1, unsigned val2, + unsigned *samples_left); +}; + +struct adc_device { + struct platform_device *pdev; + struct platform_device *owner; + struct clk *clk; + struct s3c_adc_client *cur; + struct s3c_adc_client *ts_pend; + void __iomem *regs; + spinlock_t lock; + + unsigned int prescale; + + int irq; + struct regulator *vdd; +}; + +static struct adc_device *adc_dev; + +static LIST_HEAD(adc_pending); /* protected by adc_device.lock */ + +#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg) + +static inline void s3c_adc_convert(struct adc_device *adc) +{ + unsigned con = readl(adc->regs + S3C2410_ADCCON); + + con |= S3C2410_ADCCON_ENABLE_START; + writel(con, adc->regs + S3C2410_ADCCON); +} + +static inline void s3c_adc_select(struct adc_device *adc, + struct s3c_adc_client *client) +{ + unsigned con = readl(adc->regs + S3C2410_ADCCON); + enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; + + client->select_cb(client, 1); + + if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2) + con &= ~S3C2410_ADCCON_MUXMASK; + con &= ~S3C2410_ADCCON_STDBM; + con &= ~S3C2410_ADCCON_STARTMASK; + + if (!client->is_ts) { + if (cpu == TYPE_ADCV3) + writel(client->channel & 0xf, adc->regs + S5P_ADCMUX); + else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12) + writel(client->channel & 0xf, + adc->regs + S3C2443_ADCMUX); + else + con |= S3C2410_ADCCON_SELMUX(client->channel); + } + + writel(con, adc->regs + S3C2410_ADCCON); +} + +static void s3c_adc_dbgshow(struct adc_device *adc) +{ + adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n", + readl(adc->regs + S3C2410_ADCCON), + readl(adc->regs + S3C2410_ADCTSC), + readl(adc->regs + S3C2410_ADCDLY)); +} + +static void s3c_adc_try(struct adc_device *adc) +{ + struct s3c_adc_client *next = adc->ts_pend; + + if (!next && !list_empty(&adc_pending)) { + next = list_first_entry(&adc_pending, + struct s3c_adc_client, pend); + list_del(&next->pend); + } else + adc->ts_pend = NULL; + + if (next) { + adc_dbg(adc, "new client is %p\n", next); + adc->cur = next; + s3c_adc_select(adc, next); + s3c_adc_convert(adc); + s3c_adc_dbgshow(adc); + } +} + +int s3c_adc_start(struct s3c_adc_client *client, + unsigned int channel, unsigned int nr_samples) +{ + struct adc_device *adc = adc_dev; + unsigned long flags; + + if (!adc) { + printk(KERN_ERR "%s: failed to find adc\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(&adc->lock, flags); + + if (client->is_ts && adc->ts_pend) { + spin_unlock_irqrestore(&adc->lock, flags); + return -EAGAIN; + } + + client->channel = channel; + client->nr_samples = nr_samples; + + if (client->is_ts) + adc->ts_pend = client; + else + list_add_tail(&client->pend, &adc_pending); + + if (!adc->cur) + s3c_adc_try(adc); + + spin_unlock_irqrestore(&adc->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_adc_start); + +static void s3c_convert_done(struct s3c_adc_client *client, + unsigned v, unsigned u, unsigned *left) +{ + client->result = v; + wake_up(client->wait); +} + +int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); + int ret; + + client->convert_cb = s3c_convert_done; + client->wait = &wake; + client->result = -1; + + ret = s3c_adc_start(client, ch, 1); + if (ret < 0) + goto err; + + ret = wait_event_timeout(wake, client->result >= 0, HZ / 2); + if (client->result < 0) { + ret = -ETIMEDOUT; + goto err; + } + + client->convert_cb = NULL; + return client->result; + +err: + return ret; +} +EXPORT_SYMBOL_GPL(s3c_adc_read); + +static void s3c_adc_default_select(struct s3c_adc_client *client, + unsigned select) +{ +} + +struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, + void (*select)(struct s3c_adc_client *client, + unsigned int selected), + void (*conv)(struct s3c_adc_client *client, + unsigned d0, unsigned d1, + unsigned *samples_left), + unsigned int is_ts) +{ + struct s3c_adc_client *client; + + WARN_ON(!pdev); + + if (!select) + select = s3c_adc_default_select; + + if (!pdev) + return ERR_PTR(-EINVAL); + + client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL); + if (!client) { + dev_err(&pdev->dev, "no memory for adc client\n"); + return ERR_PTR(-ENOMEM); + } + + client->pdev = pdev; + client->is_ts = is_ts; + client->select_cb = select; + client->convert_cb = conv; + + return client; +} +EXPORT_SYMBOL_GPL(s3c_adc_register); + +void s3c_adc_release(struct s3c_adc_client *client) +{ + unsigned long flags; + + spin_lock_irqsave(&adc_dev->lock, flags); + + /* We should really check that nothing is in progress. */ + if (adc_dev->cur == client) + adc_dev->cur = NULL; + if (adc_dev->ts_pend == client) + adc_dev->ts_pend = NULL; + else { + struct list_head *p, *n; + struct s3c_adc_client *tmp; + + list_for_each_safe(p, n, &adc_pending) { + tmp = list_entry(p, struct s3c_adc_client, pend); + if (tmp == client) + list_del(&tmp->pend); + } + } + + if (adc_dev->cur == NULL) + s3c_adc_try(adc_dev); + + spin_unlock_irqrestore(&adc_dev->lock, flags); + kfree(client); +} +EXPORT_SYMBOL_GPL(s3c_adc_release); + +static irqreturn_t s3c_adc_irq(int irq, void *pw) +{ + struct adc_device *adc = pw; + struct s3c_adc_client *client = adc->cur; + enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; + unsigned data0, data1; + + if (!client) { + dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__); + goto exit; + } + + data0 = readl(adc->regs + S3C2410_ADCDAT0); + data1 = readl(adc->regs + S3C2410_ADCDAT1); + adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1); + + client->nr_samples--; + + if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) { + data0 &= 0x3ff; + data1 &= 0x3ff; + } else { + /* S3C2416/S3C64XX/S5P ADC resolution is 12-bit */ + data0 &= 0xfff; + data1 &= 0xfff; + } + + if (client->convert_cb) + (client->convert_cb)(client, data0, data1, &client->nr_samples); + + if (client->nr_samples > 0) { + /* fire another conversion for this */ + + client->select_cb(client, 1); + s3c_adc_convert(adc); + } else { + spin_lock(&adc->lock); + (client->select_cb)(client, 0); + adc->cur = NULL; + + s3c_adc_try(adc); + spin_unlock(&adc->lock); + } + +exit: + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) { + /* Clear ADC interrupt */ + writel(0, adc->regs + S3C64XX_ADCCLRINT); + } + return IRQ_HANDLED; +} + +static int s3c_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adc_device *adc; + struct resource *regs; + enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; + int ret; + unsigned tmp; + + adc = devm_kzalloc(dev, sizeof(struct adc_device), GFP_KERNEL); + if (adc == NULL) { + dev_err(dev, "failed to allocate adc_device\n"); + return -ENOMEM; + } + + spin_lock_init(&adc->lock); + + adc->pdev = pdev; + adc->prescale = S3C2410_ADCCON_PRSCVL(49); + + adc->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(adc->vdd)) { + dev_err(dev, "operating without regulator \"vdd\" .\n"); + return PTR_ERR(adc->vdd); + } + + adc->irq = platform_get_irq(pdev, 1); + if (adc->irq <= 0) { + dev_err(dev, "failed to get adc irq\n"); + return -ENOENT; + } + + ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev), + adc); + if (ret < 0) { + dev_err(dev, "failed to attach adc irq\n"); + return ret; + } + + adc->clk = devm_clk_get(dev, "adc"); + if (IS_ERR(adc->clk)) { + dev_err(dev, "failed to get adc clock\n"); + return PTR_ERR(adc->clk); + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + adc->regs = devm_ioremap_resource(dev, regs); + if (IS_ERR(adc->regs)) + return PTR_ERR(adc->regs); + + ret = regulator_enable(adc->vdd); + if (ret) + return ret; + + clk_enable(adc->clk); + + tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + if (cpu == TYPE_ADCV12) + tmp |= S3C2416_ADCCON_RESSEL; + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) + tmp |= S3C64XX_ADCCON_RESSEL; + + writel(tmp, adc->regs + S3C2410_ADCCON); + + dev_info(dev, "attached adc driver\n"); + + platform_set_drvdata(pdev, adc); + adc_dev = adc; + + return 0; +} + +static int s3c_adc_remove(struct platform_device *pdev) +{ + struct adc_device *adc = platform_get_drvdata(pdev); + + clk_disable(adc->clk); + regulator_disable(adc->vdd); + + return 0; +} + +#ifdef CONFIG_PM +static int s3c_adc_suspend(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct adc_device *adc = platform_get_drvdata(pdev); + unsigned long flags; + u32 con; + + spin_lock_irqsave(&adc->lock, flags); + + con = readl(adc->regs + S3C2410_ADCCON); + con |= S3C2410_ADCCON_STDBM; + writel(con, adc->regs + S3C2410_ADCCON); + + disable_irq(adc->irq); + spin_unlock_irqrestore(&adc->lock, flags); + clk_disable(adc->clk); + regulator_disable(adc->vdd); + + return 0; +} + +static int s3c_adc_resume(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct adc_device *adc = platform_get_drvdata(pdev); + enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; + int ret; + unsigned long tmp; + + ret = regulator_enable(adc->vdd); + if (ret) + return ret; + clk_enable(adc->clk); + enable_irq(adc->irq); + + tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + if (cpu == TYPE_ADCV12) + tmp |= S3C2416_ADCCON_RESSEL; + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) + tmp |= S3C64XX_ADCCON_RESSEL; + + writel(tmp, adc->regs + S3C2410_ADCCON); + + return 0; +} + +#else +#define s3c_adc_suspend NULL +#define s3c_adc_resume NULL +#endif + +static struct platform_device_id s3c_adc_driver_ids[] = { + { + .name = "s3c24xx-adc", + .driver_data = TYPE_ADCV1, + }, { + .name = "s3c2443-adc", + .driver_data = TYPE_ADCV11, + }, { + .name = "s3c2416-adc", + .driver_data = TYPE_ADCV12, + }, { + .name = "s3c64xx-adc", + .driver_data = TYPE_ADCV2, + }, { + .name = "samsung-adc-v3", + .driver_data = TYPE_ADCV3, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids); + +static const struct dev_pm_ops adc_pm_ops = { + .suspend = s3c_adc_suspend, + .resume = s3c_adc_resume, +}; + +static struct platform_driver s3c_adc_driver = { + .id_table = s3c_adc_driver_ids, + .driver = { + .name = "s3c-adc", + .owner = THIS_MODULE, + .pm = &adc_pm_ops, + }, + .probe = s3c_adc_probe, + .remove = s3c_adc_remove, +}; + +static int __init adc_init(void) +{ + int ret; + + ret = platform_driver_register(&s3c_adc_driver); + if (ret) + printk(KERN_ERR "%s: failed to add adc driver\n", __func__); + + return ret; +} + +module_init(adc_init); diff --git a/arch/arm/plat-samsung/clock-clksrc.c b/arch/arm/plat-samsung/clock-clksrc.c new file mode 100644 index 00000000000..786a4107a15 --- /dev/null +++ b/arch/arm/plat-samsung/clock-clksrc.c @@ -0,0 +1,212 @@ +/* linux/arch/arm/plat-samsung/clock-clksrc.c + * + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> + +#include <plat/clock.h> +#include <plat/clock-clksrc.h> +#include <plat/cpu-freq.h> + +static inline struct clksrc_clk *to_clksrc(struct clk *clk) +{ + return container_of(clk, struct clksrc_clk, clk); +} + +static inline u32 bit_mask(u32 shift, u32 nr_bits) +{ + u32 mask = 0xffffffff >> (32 - nr_bits); + + return mask << shift; +} + +static unsigned long s3c_getrate_clksrc(struct clk *clk) +{ + struct clksrc_clk *sclk = to_clksrc(clk); + unsigned long rate = clk_get_rate(clk->parent); + u32 clkdiv = __raw_readl(sclk->reg_div.reg); + u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size); + + clkdiv &= mask; + clkdiv >>= sclk->reg_div.shift; + clkdiv++; + + rate /= clkdiv; + return rate; +} + +static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate) +{ + struct clksrc_clk *sclk = to_clksrc(clk); + void __iomem *reg = sclk->reg_div.reg; + unsigned int div; + u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size); + u32 val; + + rate = clk_round_rate(clk, rate); + div = clk_get_rate(clk->parent) / rate; + if (div > (1 << sclk->reg_div.size)) + return -EINVAL; + + val = __raw_readl(reg); + val &= ~mask; + val |= (div - 1) << sclk->reg_div.shift; + __raw_writel(val, reg); + + return 0; +} + +static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent) +{ + struct clksrc_clk *sclk = to_clksrc(clk); + struct clksrc_sources *srcs = sclk->sources; + u32 clksrc = __raw_readl(sclk->reg_src.reg); + u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size); + int src_nr = -1; + int ptr; + + for (ptr = 0; ptr < srcs->nr_sources; ptr++) + if (srcs->sources[ptr] == parent) { + src_nr = ptr; + break; + } + + if (src_nr >= 0) { + clk->parent = parent; + + clksrc &= ~mask; + clksrc |= src_nr << sclk->reg_src.shift; + + __raw_writel(clksrc, sclk->reg_src.reg); + return 0; + } + + return -EINVAL; +} + +static unsigned long s3c_roundrate_clksrc(struct clk *clk, + unsigned long rate) +{ + struct clksrc_clk *sclk = to_clksrc(clk); + unsigned long parent_rate = clk_get_rate(clk->parent); + int max_div = 1 << sclk->reg_div.size; + int div; + + if (rate >= parent_rate) + rate = parent_rate; + else { + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div == 0) + div = 1; + if (div > max_div) + div = max_div; + + rate = parent_rate / div; + } + + return rate; +} + +/* Clock initialisation code */ + +void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce) +{ + struct clksrc_sources *srcs = clk->sources; + u32 mask = bit_mask(clk->reg_src.shift, clk->reg_src.size); + u32 clksrc; + + if (!clk->reg_src.reg) { + if (!clk->clk.parent) + printk(KERN_ERR "%s: no parent clock specified\n", + clk->clk.name); + return; + } + + clksrc = __raw_readl(clk->reg_src.reg); + clksrc &= mask; + clksrc >>= clk->reg_src.shift; + + if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) { + printk(KERN_ERR "%s: bad source %d\n", + clk->clk.name, clksrc); + return; + } + + clk->clk.parent = srcs->sources[clksrc]; + + if (announce) + printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n", + clk->clk.name, clk->clk.parent->name, clksrc, + clk_get_rate(&clk->clk)); +} + +static struct clk_ops clksrc_ops = { + .set_parent = s3c_setparent_clksrc, + .get_rate = s3c_getrate_clksrc, + .set_rate = s3c_setrate_clksrc, + .round_rate = s3c_roundrate_clksrc, +}; + +static struct clk_ops clksrc_ops_nodiv = { + .set_parent = s3c_setparent_clksrc, +}; + +static struct clk_ops clksrc_ops_nosrc = { + .get_rate = s3c_getrate_clksrc, + .set_rate = s3c_setrate_clksrc, + .round_rate = s3c_roundrate_clksrc, +}; + +void __init s3c_register_clksrc(struct clksrc_clk *clksrc, int size) +{ + int ret; + + for (; size > 0; size--, clksrc++) { + if (!clksrc->reg_div.reg && !clksrc->reg_src.reg) + printk(KERN_ERR "%s: clock %s has no registers set\n", + __func__, clksrc->clk.name); + + /* fill in the default functions */ + + if (!clksrc->clk.ops) { + if (!clksrc->reg_div.reg) + clksrc->clk.ops = &clksrc_ops_nodiv; + else if (!clksrc->reg_src.reg) + clksrc->clk.ops = &clksrc_ops_nosrc; + else + clksrc->clk.ops = &clksrc_ops; + } + + /* setup the clocksource, but do not announce it + * as it may be re-set by the setup routines + * called after the rest of the clocks have been + * registered + */ + s3c_set_clksrc(clksrc, false); + + ret = s3c24xx_register_clock(&clksrc->clk); + + if (ret < 0) { + printk(KERN_ERR "%s: failed to register %s (%d)\n", + __func__, clksrc->clk.name, ret); + } + } +} diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c new file mode 100644 index 00000000000..d103ac1a52a --- /dev/null +++ b/arch/arm/plat-samsung/clock.c @@ -0,0 +1,539 @@ +/* linux/arch/arm/plat-s3c24xx/clock.c + * + * Copyright 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX Core clock control support + * + * Based on, and code from linux/arch/arm/mach-versatile/clock.c + ** + ** Copyright (C) 2004 ARM Limited. + ** Written by Deep Blue Solutions Limited. + * + * + * 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 +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#if defined(CONFIG_DEBUG_FS) +#include <linux/debugfs.h> +#endif + +#include <asm/irq.h> + +#include <plat/cpu-freq.h> + +#include <plat/clock.h> +#include <plat/cpu.h> + +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> /* for s3c24xx_uart_devs */ + +/* clock information */ + +static LIST_HEAD(clocks); + +/* We originally used an mutex here, but some contexts (see resume) + * are calling functions such as clk_set_parent() with IRQs disabled + * causing an BUG to be triggered. + */ +DEFINE_SPINLOCK(clocks_lock); + +/* Global watchdog clock used by arch_wtd_reset() callback */ +struct clk *s3c2410_wdtclk; +static int __init s3c_wdt_reset_init(void) +{ + s3c2410_wdtclk = clk_get(NULL, "watchdog"); + if (IS_ERR(s3c2410_wdtclk)) + printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__); + return 0; +} +arch_initcall(s3c_wdt_reset_init); + +/* enable and disable calls for use with the clk struct */ + +static int clk_null_enable(struct clk *clk, int enable) +{ + return 0; +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (IS_ERR(clk) || clk == NULL) + return -EINVAL; + + clk_enable(clk->parent); + + spin_lock_irqsave(&clocks_lock, flags); + + if ((clk->usage++) == 0) + (clk->enable)(clk, 1); + + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (IS_ERR(clk) || clk == NULL) + return; + + spin_lock_irqsave(&clocks_lock, flags); + + if ((--clk->usage) == 0) + (clk->enable)(clk, 0); + + spin_unlock_irqrestore(&clocks_lock, flags); + clk_disable(clk->parent); +} + + +unsigned long clk_get_rate(struct clk *clk) +{ + if (IS_ERR_OR_NULL(clk)) + return 0; + + if (clk->rate != 0) + return clk->rate; + + if (clk->ops != NULL && clk->ops->get_rate != NULL) + return (clk->ops->get_rate)(clk); + + if (clk->parent != NULL) + return clk_get_rate(clk->parent); + + return clk->rate; +} + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate) + return (clk->ops->round_rate)(clk, rate); + + return rate; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + int ret; + + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + /* We do not default just do a clk->rate = rate as + * the clock may have been made this way by choice. + */ + + WARN_ON(clk->ops == NULL); + WARN_ON(clk->ops && clk->ops->set_rate == NULL); + + if (clk->ops == NULL || clk->ops->set_rate == NULL) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + ret = (clk->ops->set_rate)(clk, rate); + spin_unlock_irqrestore(&clocks_lock, flags); + + return ret; +} + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + int ret = 0; + + if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(parent)) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + + if (clk->ops && clk->ops->set_parent) + ret = (clk->ops->set_parent)(clk, parent); + + spin_unlock_irqrestore(&clocks_lock, flags); + + return ret; +} + +EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_get_rate); +EXPORT_SYMBOL(clk_round_rate); +EXPORT_SYMBOL(clk_set_rate); +EXPORT_SYMBOL(clk_get_parent); +EXPORT_SYMBOL(clk_set_parent); + +/* base clocks */ + +int clk_default_setrate(struct clk *clk, unsigned long rate) +{ + clk->rate = rate; + return 0; +} + +struct clk_ops clk_ops_def_setrate = { + .set_rate = clk_default_setrate, +}; + +struct clk clk_xtal = { + .name = "xtal", + .rate = 0, + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_ext = { + .name = "ext", +}; + +struct clk clk_epll = { + .name = "epll", +}; + +struct clk clk_mpll = { + .name = "mpll", + .ops = &clk_ops_def_setrate, +}; + +struct clk clk_upll = { + .name = "upll", + .parent = NULL, + .ctrlbit = 0, +}; + +struct clk clk_f = { + .name = "fclk", + .rate = 0, + .parent = &clk_mpll, + .ctrlbit = 0, +}; + +struct clk clk_h = { + .name = "hclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0, + .ops = &clk_ops_def_setrate, +}; + +struct clk clk_p = { + .name = "pclk", + .rate = 0, + .parent = NULL, + .ctrlbit = 0, + .ops = &clk_ops_def_setrate, +}; + +struct clk clk_usb_bus = { + .name = "usb-bus", + .rate = 0, + .parent = &clk_upll, +}; + + +struct clk s3c24xx_uclk = { + .name = "uclk", +}; + +/* initialise the clock system */ + +/** + * s3c24xx_register_clock() - register a clock + * @clk: The clock to register + * + * Add the specified clock to the list of clocks known by the system. + */ +int s3c24xx_register_clock(struct clk *clk) +{ + if (clk->enable == NULL) + clk->enable = clk_null_enable; + + /* fill up the clk_lookup structure and register it*/ + clk->lookup.dev_id = clk->devname; + clk->lookup.con_id = clk->name; + clk->lookup.clk = clk; + clkdev_add(&clk->lookup); + + return 0; +} + +/** + * s3c24xx_register_clocks() - register an array of clock pointers + * @clks: Pointer to an array of struct clk pointers + * @nr_clks: The number of clocks in the @clks array. + * + * Call s3c24xx_register_clock() for all the clock pointers contained + * in the @clks list. Returns the number of failures. + */ +int s3c24xx_register_clocks(struct clk **clks, int nr_clks) +{ + int fails = 0; + + for (; nr_clks > 0; nr_clks--, clks++) { + if (s3c24xx_register_clock(*clks) < 0) { + struct clk *clk = *clks; + printk(KERN_ERR "%s: failed to register %p: %s\n", + __func__, clk, clk->name); + fails++; + } + } + + return fails; +} + +/** + * s3c_register_clocks() - register an array of clocks + * @clkp: Pointer to the first clock in the array. + * @nr_clks: Number of clocks to register. + * + * Call s3c24xx_register_clock() on the @clkp array given, printing an + * error if it fails to register the clock (unlikely). + */ +void __init s3c_register_clocks(struct clk *clkp, int nr_clks) +{ + int ret; + + for (; nr_clks > 0; nr_clks--, clkp++) { + ret = s3c24xx_register_clock(clkp); + + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } +} + +/** + * s3c_disable_clocks() - disable an array of clocks + * @clkp: Pointer to the first clock in the array. + * @nr_clks: Number of clocks to register. + * + * for internal use only at initialisation time. disable the clocks in the + * @clkp array. + */ + +void __init s3c_disable_clocks(struct clk *clkp, int nr_clks) +{ + for (; nr_clks > 0; nr_clks--, clkp++) + (clkp->enable)(clkp, 0); +} + +/* initialise all the clocks */ + +int __init s3c24xx_register_baseclocks(unsigned long xtal) +{ + printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n"); + + clk_xtal.rate = xtal; + + /* register our clocks */ + + if (s3c24xx_register_clock(&clk_xtal) < 0) + printk(KERN_ERR "failed to register master xtal\n"); + + if (s3c24xx_register_clock(&clk_mpll) < 0) + printk(KERN_ERR "failed to register mpll clock\n"); + + if (s3c24xx_register_clock(&clk_upll) < 0) + printk(KERN_ERR "failed to register upll clock\n"); + + if (s3c24xx_register_clock(&clk_f) < 0) + printk(KERN_ERR "failed to register cpu fclk\n"); + + if (s3c24xx_register_clock(&clk_h) < 0) + printk(KERN_ERR "failed to register cpu hclk\n"); + + if (s3c24xx_register_clock(&clk_p) < 0) + printk(KERN_ERR "failed to register cpu pclk\n"); + + return 0; +} + +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) +/* debugfs support to trace clock tree hierarchy and attributes */ + +static struct dentry *clk_debugfs_root; + +static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) +{ + struct clk *child; + const char *state; + char buf[255] = { 0 }; + int n = 0; + + if (c->name) + n = snprintf(buf, sizeof(buf) - 1, "%s", c->name); + + if (c->devname) + n += snprintf(buf + n, sizeof(buf) - 1 - n, ":%s", c->devname); + + state = (c->usage > 0) ? "on" : "off"; + + seq_printf(s, "%*s%-*s %-6s %-3d %-10lu\n", + level * 3 + 1, "", + 50 - level * 3, buf, + state, c->usage, clk_get_rate(c)); + + list_for_each_entry(child, &clocks, list) { + if (child->parent != c) + continue; + + clock_tree_show_one(s, child, level + 1); + } +} + +static int clock_tree_show(struct seq_file *s, void *data) +{ + struct clk *c; + unsigned long flags; + + seq_printf(s, " clock state ref rate\n"); + seq_printf(s, "----------------------------------------------------\n"); + + spin_lock_irqsave(&clocks_lock, flags); + + list_for_each_entry(c, &clocks, list) + if (c->parent == NULL) + clock_tree_show_one(s, c, 0); + + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} + +static int clock_tree_open(struct inode *inode, struct file *file) +{ + return single_open(file, clock_tree_show, inode->i_private); +} + +static const struct file_operations clock_tree_fops = { + .open = clock_tree_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int clock_rate_show(void *data, u64 *val) +{ + struct clk *c = data; + *val = clk_get_rate(c); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_rate_show, NULL, "%llu\n"); + +static int clk_debugfs_register_one(struct clk *c) +{ + int err; + struct dentry *d; + struct clk *pa = c->parent; + char s[255]; + char *p = s; + + p += sprintf(p, "%s", c->devname); + + d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); + if (!d) + return -ENOMEM; + + c->dent = d; + + d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usage); + if (!d) { + err = -ENOMEM; + goto err_out; + } + + d = debugfs_create_file("rate", S_IRUGO, c->dent, c, &clock_rate_fops); + if (!d) { + err = -ENOMEM; + goto err_out; + } + return 0; + +err_out: + debugfs_remove_recursive(c->dent); + return err; +} + +static int clk_debugfs_register(struct clk *c) +{ + int err; + struct clk *pa = c->parent; + + if (pa && !pa->dent) { + err = clk_debugfs_register(pa); + if (err) + return err; + } + + if (!c->dent) { + err = clk_debugfs_register_one(c); + if (err) + return err; + } + return 0; +} + +static int __init clk_debugfs_init(void) +{ + struct clk *c; + struct dentry *d; + int err = -ENOMEM; + + d = debugfs_create_dir("clock", NULL); + if (!d) + return -ENOMEM; + clk_debugfs_root = d; + + d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL, + &clock_tree_fops); + if (!d) + goto err_out; + + list_for_each_entry(c, &clocks, list) { + err = clk_debugfs_register(c); + if (err) + goto err_out; + } + return 0; + +err_out: + debugfs_remove_recursive(clk_debugfs_root); + return err; +} +late_initcall(clk_debugfs_init); + +#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */ diff --git a/arch/arm/plat-samsung/cpu.c b/arch/arm/plat-samsung/cpu.c new file mode 100644 index 00000000000..364963a0a34 --- /dev/null +++ b/arch/arm/plat-samsung/cpu.c @@ -0,0 +1,50 @@ +/* linux/arch/arm/plat-samsung/cpu.c + * + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CPU Support + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + + +#include <mach/map.h> +#include <plat/cpu.h> + +unsigned long samsung_cpu_id; +static unsigned int samsung_cpu_rev; + +unsigned int samsung_rev(void) +{ + return samsung_cpu_rev; +} +EXPORT_SYMBOL(samsung_rev); + +void __init s3c64xx_init_cpu(void) +{ + samsung_cpu_id = __raw_readl(S3C_VA_SYS + 0x118); + if (!samsung_cpu_id) { + /* + * S3C6400 has the ID register in a different place, + * and needs a write before it can be read. + */ + __raw_writel(0x0, S3C_VA_SYS + 0xA1C); + samsung_cpu_id = __raw_readl(S3C_VA_SYS + 0xA1C); + } + + samsung_cpu_rev = 0; +} + +void __init s5p_init_cpu(void __iomem *cpuid_addr) +{ + samsung_cpu_id = __raw_readl(cpuid_addr); + samsung_cpu_rev = samsung_cpu_id & 0xFF; +} diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c new file mode 100644 index 00000000000..2157c5b539e --- /dev/null +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -0,0 +1,152 @@ +/* linux/arch/arm/plat-samsung/dev-backlight.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Common infrastructure for PWM Backlight for Samsung boards + * + * 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/gpio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/pwm_backlight.h> + +#include <plat/devs.h> +#include <plat/gpio-cfg.h> +#include <plat/backlight.h> + +struct samsung_bl_drvdata { + struct platform_pwm_backlight_data plat_data; + struct samsung_bl_gpio_info *gpio_info; +}; + +static int samsung_bl_init(struct device *dev) +{ + int ret = 0; + struct platform_pwm_backlight_data *pdata = dev->platform_data; + struct samsung_bl_drvdata *drvdata = container_of(pdata, + struct samsung_bl_drvdata, plat_data); + struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info; + + ret = gpio_request(bl_gpio_info->no, "Backlight"); + if (ret) { + printk(KERN_ERR "failed to request GPIO for LCD Backlight\n"); + return ret; + } + + /* Configure GPIO pin with specific GPIO function for PWM timer */ + s3c_gpio_cfgpin(bl_gpio_info->no, bl_gpio_info->func); + + return 0; +} + +static void samsung_bl_exit(struct device *dev) +{ + struct platform_pwm_backlight_data *pdata = dev->platform_data; + struct samsung_bl_drvdata *drvdata = container_of(pdata, + struct samsung_bl_drvdata, plat_data); + struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info; + + s3c_gpio_cfgpin(bl_gpio_info->no, S3C_GPIO_OUTPUT); + gpio_free(bl_gpio_info->no); +} + +/* Initialize few important fields of platform_pwm_backlight_data + * structure with default values. These fields can be overridden by + * board-specific values sent from machine file. + * For ease of operation, these fields are initialized with values + * used by most samsung boards. + * Users has the option of sending info about other parameters + * for their specific boards + */ + +static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = { + .plat_data = { + .max_brightness = 255, + .dft_brightness = 255, + .pwm_period_ns = 78770, + .enable_gpio = -1, + .init = samsung_bl_init, + .exit = samsung_bl_exit, + }, +}; + +static struct platform_device samsung_dfl_bl_device __initdata = { + .name = "pwm-backlight", +}; + +/* samsung_bl_set - Set board specific data (if any) provided by user for + * PWM Backlight control and register specific PWM and backlight device. + * @gpio_info: structure containing GPIO info for PWM timer + * @bl_data: structure containing Backlight control data + */ +void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, + struct platform_pwm_backlight_data *bl_data) +{ + int ret = 0; + struct platform_device *samsung_bl_device; + struct samsung_bl_drvdata *samsung_bl_drvdata; + struct platform_pwm_backlight_data *samsung_bl_data; + + samsung_bl_device = kmemdup(&samsung_dfl_bl_device, + sizeof(struct platform_device), GFP_KERNEL); + if (!samsung_bl_device) { + printk(KERN_ERR "%s: no memory for platform dev\n", __func__); + return; + } + + samsung_bl_drvdata = kmemdup(&samsung_dfl_bl_data, + sizeof(samsung_dfl_bl_data), GFP_KERNEL); + if (!samsung_bl_drvdata) { + printk(KERN_ERR "%s: no memory for platform dev\n", __func__); + goto err_data; + } + samsung_bl_device->dev.platform_data = &samsung_bl_drvdata->plat_data; + samsung_bl_drvdata->gpio_info = gpio_info; + samsung_bl_data = &samsung_bl_drvdata->plat_data; + + /* Copy board specific data provided by user */ + samsung_bl_data->pwm_id = bl_data->pwm_id; + samsung_bl_device->dev.parent = &samsung_device_pwm.dev; + + if (bl_data->max_brightness) + samsung_bl_data->max_brightness = bl_data->max_brightness; + if (bl_data->dft_brightness) + samsung_bl_data->dft_brightness = bl_data->dft_brightness; + if (bl_data->lth_brightness) + samsung_bl_data->lth_brightness = bl_data->lth_brightness; + if (bl_data->pwm_period_ns) + samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns; + if (bl_data->enable_gpio >= 0) + samsung_bl_data->enable_gpio = bl_data->enable_gpio; + if (bl_data->init) + samsung_bl_data->init = bl_data->init; + if (bl_data->notify) + samsung_bl_data->notify = bl_data->notify; + if (bl_data->notify_after) + samsung_bl_data->notify_after = bl_data->notify_after; + if (bl_data->exit) + samsung_bl_data->exit = bl_data->exit; + if (bl_data->check_fb) + samsung_bl_data->check_fb = bl_data->check_fb; + + /* Register the Backlight dev */ + ret = platform_device_register(samsung_bl_device); + if (ret) { + printk(KERN_ERR "failed to register backlight device: %d\n", ret); + goto err_plat_reg2; + } + + return; + +err_plat_reg2: + kfree(samsung_bl_data); +err_data: + kfree(samsung_bl_device); + return; +} diff --git a/arch/arm/plat-samsung/dev-uart.c b/arch/arm/plat-samsung/dev-uart.c new file mode 100644 index 00000000000..5928105490f --- /dev/null +++ b/arch/arm/plat-samsung/dev-uart.c @@ -0,0 +1,46 @@ +/* linux/arch/arm/plat-samsung/dev-uart.c + * originally from arch/arm/plat-s3c24xx/devs.c + *x + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Base S3C24XX platform device definitions + * + * 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/platform_device.h> + +#include <plat/devs.h> + +/* uart devices */ + +static struct platform_device s3c24xx_uart_device0 = { + .id = 0, +}; + +static struct platform_device s3c24xx_uart_device1 = { + .id = 1, +}; + +static struct platform_device s3c24xx_uart_device2 = { + .id = 2, +}; + +static struct platform_device s3c24xx_uart_device3 = { + .id = 3, +}; + +struct platform_device *s3c24xx_uart_src[4] = { + &s3c24xx_uart_device0, + &s3c24xx_uart_device1, + &s3c24xx_uart_device2, + &s3c24xx_uart_device3, +}; + +struct platform_device *s3c24xx_uart_devs[4] = { +}; diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c new file mode 100644 index 00000000000..ead4f1c9405 --- /dev/null +++ b/arch/arm/plat-samsung/devs.c @@ -0,0 +1,1559 @@ +/* linux/arch/arm/plat-samsung/devs.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Base SAMSUNG platform device definitions + * + * 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/amba/pl330.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/dma-mapping.h> +#include <linux/fb.h> +#include <linux/gfp.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/onenand.h> +#include <linux/mtd/partitions.h> +#include <linux/mmc/host.h> +#include <linux/ioport.h> +#include <linux/sizes.h> +#include <linux/platform_data/s3c-hsudc.h> +#include <linux/platform_data/s3c-hsotg.h> +#include <linux/platform_data/dma-s3c24xx.h> + +#include <media/s5p_hdmi.h> + +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/dma.h> +#include <mach/irqs.h> +#include <mach/map.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/adc.h> +#include <linux/platform_data/ata-samsung_cf.h> +#include <plat/fb.h> +#include <plat/fb-s3c2410.h> +#include <plat/hdmi.h> +#include <linux/platform_data/hwmon-s3c.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <plat/keypad.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <plat/pwm-core.h> +#include <plat/sdhci.h> +#include <linux/platform_data/touchscreen-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include <plat/usb-phy.h> +#include <plat/regs-spi.h> +#include <linux/platform_data/spi-s3c64xx.h> + +static u64 samsung_device_dma_mask = DMA_BIT_MASK(32); + +/* AC97 */ +#ifdef CONFIG_CPU_S3C2440 +static struct resource s3c_ac97_resource[] = { + [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97), + [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97), + [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"), + [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"), + [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"), +}; + +struct platform_device s3c_device_ac97 = { + .name = "samsung-ac97", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_ac97_resource), + .resource = s3c_ac97_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_CPU_S3C2440 */ + +/* ADC */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_adc_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), + [1] = DEFINE_RES_IRQ(IRQ_TC), + [2] = DEFINE_RES_IRQ(IRQ_ADC), +}; + +struct platform_device s3c_device_adc = { + .name = "s3c24xx-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +#if defined(CONFIG_SAMSUNG_DEV_ADC) +static struct resource s3c_adc_resource[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_TC), + [2] = DEFINE_RES_IRQ(IRQ_ADC), +}; + +struct platform_device s3c_device_adc = { + .name = "samsung-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; +#endif /* CONFIG_SAMSUNG_DEV_ADC */ + +/* Camif Controller */ + +#ifdef CONFIG_CPU_S3C2440 +static struct resource s3c_camif_resource[] = { + [0] = DEFINE_RES_MEM(S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF), + [1] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_C), + [2] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_P), +}; + +struct platform_device s3c_device_camif = { + .name = "s3c2440-camif", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_camif_resource), + .resource = s3c_camif_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_CPU_S3C2440 */ + +/* ASOC DMA */ + +#ifdef CONFIG_PLAT_S5P +static struct resource samsung_asoc_idma_resource = DEFINE_RES_IRQ(IRQ_I2S0); + +struct platform_device samsung_asoc_idma = { + .name = "samsung-idma", + .id = -1, + .num_resources = 1, + .resource = &samsung_asoc_idma_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif + +/* FB */ + +#ifdef CONFIG_S3C_DEV_FB +static struct resource s3c_fb_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC), + [2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO), + [3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM), +}; + +struct platform_device s3c_device_fb = { + .name = "s3c-fb", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_fb_resource), + .resource = s3c_fb_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd) +{ + s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata), + &s3c_device_fb); +} +#endif /* CONFIG_S3C_DEV_FB */ + +/* FIMC */ + +#ifdef CONFIG_S5P_DEV_FIMC0 +static struct resource s5p_fimc0_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_FIMC0, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_FIMC0), +}; + +struct platform_device s5p_device_fimc0 = { + .name = "s5p-fimc", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_fimc0_resource), + .resource = s5p_fimc0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct platform_device s5p_device_fimc_md = { + .name = "s5p-fimc-md", + .id = -1, +}; +#endif /* CONFIG_S5P_DEV_FIMC0 */ + +#ifdef CONFIG_S5P_DEV_FIMC1 +static struct resource s5p_fimc1_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_FIMC1, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_FIMC1), +}; + +struct platform_device s5p_device_fimc1 = { + .name = "s5p-fimc", + .id = 1, + .num_resources = ARRAY_SIZE(s5p_fimc1_resource), + .resource = s5p_fimc1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_FIMC1 */ + +#ifdef CONFIG_S5P_DEV_FIMC2 +static struct resource s5p_fimc2_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_FIMC2, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_FIMC2), +}; + +struct platform_device s5p_device_fimc2 = { + .name = "s5p-fimc", + .id = 2, + .num_resources = ARRAY_SIZE(s5p_fimc2_resource), + .resource = s5p_fimc2_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_FIMC2 */ + +#ifdef CONFIG_S5P_DEV_FIMC3 +static struct resource s5p_fimc3_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_FIMC3, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_FIMC3), +}; + +struct platform_device s5p_device_fimc3 = { + .name = "s5p-fimc", + .id = 3, + .num_resources = ARRAY_SIZE(s5p_fimc3_resource), + .resource = s5p_fimc3_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_FIMC3 */ + +/* G2D */ + +#ifdef CONFIG_S5P_DEV_G2D +static struct resource s5p_g2d_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_G2D, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_2D), +}; + +struct platform_device s5p_device_g2d = { + .name = "s5p-g2d", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_g2d_resource), + .resource = s5p_g2d_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_G2D */ + +#ifdef CONFIG_S5P_DEV_JPEG +static struct resource s5p_jpeg_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_JPEG), +}; + +struct platform_device s5p_device_jpeg = { + .name = "s5p-jpeg", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_jpeg_resource), + .resource = s5p_jpeg_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_JPEG */ + +/* FIMD0 */ + +#ifdef CONFIG_S5P_DEV_FIMD0 +static struct resource s5p_fimd0_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_FIMD0, SZ_32K), + [1] = DEFINE_RES_IRQ_NAMED(IRQ_FIMD0_VSYNC, "vsync"), + [2] = DEFINE_RES_IRQ_NAMED(IRQ_FIMD0_FIFO, "fifo"), + [3] = DEFINE_RES_IRQ_NAMED(IRQ_FIMD0_SYSTEM, "lcd_sys"), +}; + +struct platform_device s5p_device_fimd0 = { + .name = "s5p-fb", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_fimd0_resource), + .resource = s5p_fimd0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd) +{ + s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata), + &s5p_device_fimd0); +} +#endif /* CONFIG_S5P_DEV_FIMD0 */ + +/* HWMON */ + +#ifdef CONFIG_S3C_DEV_HWMON +struct platform_device s3c_device_hwmon = { + .name = "s3c-hwmon", + .id = -1, + .dev.parent = &s3c_device_adc.dev, +}; + +void __init s3c_hwmon_set_platdata(struct s3c_hwmon_pdata *pd) +{ + s3c_set_platdata(pd, sizeof(struct s3c_hwmon_pdata), + &s3c_device_hwmon); +} +#endif /* CONFIG_S3C_DEV_HWMON */ + +/* HSMMC */ + +#ifdef CONFIG_S3C_DEV_HSMMC +static struct resource s3c_hsmmc_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC0, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC0), +}; + +struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc0 = { + .name = "s3c-sdhci", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_hsmmc_resource), + .resource = s3c_hsmmc_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc0_def_platdata, + }, +}; + +void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc0_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC */ + +#ifdef CONFIG_S3C_DEV_HSMMC1 +static struct resource s3c_hsmmc1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC1, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC1), +}; + +struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc1 = { + .name = "s3c-sdhci", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_hsmmc1_resource), + .resource = s3c_hsmmc1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc1_def_platdata, + }, +}; + +void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc1_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC1 */ + +/* HSMMC2 */ + +#ifdef CONFIG_S3C_DEV_HSMMC2 +static struct resource s3c_hsmmc2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC2, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC2), +}; + +struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc2 = { + .name = "s3c-sdhci", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_hsmmc2_resource), + .resource = s3c_hsmmc2_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc2_def_platdata, + }, +}; + +void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc2_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC2 */ + +#ifdef CONFIG_S3C_DEV_HSMMC3 +static struct resource s3c_hsmmc3_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC3, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC3), +}; + +struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc3 = { + .name = "s3c-sdhci", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_hsmmc3_resource), + .resource = s3c_hsmmc3_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc3_def_platdata, + }, +}; + +void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc3_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC3 */ + +/* I2C */ + +static struct resource s3c_i2c0_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC), +}; + +struct platform_device s3c_device_i2c0 = { + .name = "s3c2410-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_i2c0_resource), + .resource = s3c_i2c0_resource, +}; + +struct s3c2410_platform_i2c default_i2c_data __initdata = { + .flags = 0, + .slave_addr = 0x10, + .frequency = 100*1000, + .sda_delay = 100, +}; + +void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 0; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c0); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c0_cfg_gpio; +} + +#ifdef CONFIG_S3C_DEV_I2C1 +static struct resource s3c_i2c1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC1, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC1), +}; + +struct platform_device s3c_device_i2c1 = { + .name = "s3c2410-i2c", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_i2c1_resource), + .resource = s3c_i2c1_resource, +}; + +void __init s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 1; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c1); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c1_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C1 */ + +#ifdef CONFIG_S3C_DEV_I2C2 +static struct resource s3c_i2c2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC2, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC2), +}; + +struct platform_device s3c_device_i2c2 = { + .name = "s3c2410-i2c", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_i2c2_resource), + .resource = s3c_i2c2_resource, +}; + +void __init s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 2; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c2); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c2_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C2 */ + +#ifdef CONFIG_S3C_DEV_I2C3 +static struct resource s3c_i2c3_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC3, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC3), +}; + +struct platform_device s3c_device_i2c3 = { + .name = "s3c2440-i2c", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_i2c3_resource), + .resource = s3c_i2c3_resource, +}; + +void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 3; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c3); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c3_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C3 */ + +#ifdef CONFIG_S3C_DEV_I2C4 +static struct resource s3c_i2c4_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC4, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC4), +}; + +struct platform_device s3c_device_i2c4 = { + .name = "s3c2440-i2c", + .id = 4, + .num_resources = ARRAY_SIZE(s3c_i2c4_resource), + .resource = s3c_i2c4_resource, +}; + +void __init s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 4; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c4); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c4_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C4 */ + +#ifdef CONFIG_S3C_DEV_I2C5 +static struct resource s3c_i2c5_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC5, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC5), +}; + +struct platform_device s3c_device_i2c5 = { + .name = "s3c2440-i2c", + .id = 5, + .num_resources = ARRAY_SIZE(s3c_i2c5_resource), + .resource = s3c_i2c5_resource, +}; + +void __init s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 5; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c5); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c5_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C5 */ + +#ifdef CONFIG_S3C_DEV_I2C6 +static struct resource s3c_i2c6_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC6, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC6), +}; + +struct platform_device s3c_device_i2c6 = { + .name = "s3c2440-i2c", + .id = 6, + .num_resources = ARRAY_SIZE(s3c_i2c6_resource), + .resource = s3c_i2c6_resource, +}; + +void __init s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 6; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c6); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c6_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C6 */ + +#ifdef CONFIG_S3C_DEV_I2C7 +static struct resource s3c_i2c7_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC7, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC7), +}; + +struct platform_device s3c_device_i2c7 = { + .name = "s3c2440-i2c", + .id = 7, + .num_resources = ARRAY_SIZE(s3c_i2c7_resource), + .resource = s3c_i2c7_resource, +}; + +void __init s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 7; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s3c_device_i2c7); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c7_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C7 */ + +/* I2C HDMIPHY */ + +#ifdef CONFIG_S5P_DEV_I2C_HDMIPHY +static struct resource s5p_i2c_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_IIC_HDMIPHY, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC_HDMIPHY), +}; + +struct platform_device s5p_device_i2c_hdmiphy = { + .name = "s3c2440-hdmiphy-i2c", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_i2c_resource), + .resource = s5p_i2c_resource, +}; + +void __init s5p_i2c_hdmiphy_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + + if (soc_is_s5pv210()) + pd->bus_num = 3; + else + pd->bus_num = 0; + } + + npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), + &s5p_device_i2c_hdmiphy); +} + +static struct s5p_hdmi_platform_data s5p_hdmi_def_platdata; + +void __init s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info, + struct i2c_board_info *mhl_info, int mhl_bus) +{ + struct s5p_hdmi_platform_data *pd = &s5p_hdmi_def_platdata; + + if (soc_is_s5pv210()) + pd->hdmiphy_bus = 3; + else + pd->hdmiphy_bus = 0; + + pd->hdmiphy_info = hdmiphy_info; + pd->mhl_info = mhl_info; + pd->mhl_bus = mhl_bus; + + s3c_set_platdata(pd, sizeof(struct s5p_hdmi_platform_data), + &s5p_device_hdmi); +} + +#endif /* CONFIG_S5P_DEV_I2C_HDMIPHY */ + +/* I2S */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_iis_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS), +}; + +struct platform_device s3c_device_iis = { + .name = "s3c24xx-iis", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_iis_resource), + .resource = s3c_iis_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +/* IDE CFCON */ + +#ifdef CONFIG_SAMSUNG_DEV_IDE +static struct resource s3c_cfcon_resource[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_CFCON, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_CFCON), +}; + +struct platform_device s3c_device_cfcon = { + .id = 0, + .num_resources = ARRAY_SIZE(s3c_cfcon_resource), + .resource = s3c_cfcon_resource, +}; + +void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata), + &s3c_device_cfcon); +} +#endif /* CONFIG_SAMSUNG_DEV_IDE */ + +/* KEYPAD */ + +#ifdef CONFIG_SAMSUNG_DEV_KEYPAD +static struct resource samsung_keypad_resources[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_KEYPAD, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_KEYPAD), +}; + +struct platform_device samsung_device_keypad = { + .name = "samsung-keypad", + .id = -1, + .num_resources = ARRAY_SIZE(samsung_keypad_resources), + .resource = samsung_keypad_resources, +}; + +void __init samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd) +{ + struct samsung_keypad_platdata *npd; + + npd = s3c_set_platdata(pd, sizeof(struct samsung_keypad_platdata), + &samsung_device_keypad); + + if (!npd->cfg_gpio) + npd->cfg_gpio = samsung_keypad_cfg_gpio; +} +#endif /* CONFIG_SAMSUNG_DEV_KEYPAD */ + +/* LCD Controller */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_lcd_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_LCD, S3C24XX_SZ_LCD), + [1] = DEFINE_RES_IRQ(IRQ_LCD), +}; + +struct platform_device s3c_device_lcd = { + .name = "s3c2410-lcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_lcd_resource), + .resource = s3c_lcd_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd) +{ + struct s3c2410fb_mach_info *npd; + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_lcd); + if (npd) { + npd->displays = kmemdup(pd->displays, + sizeof(struct s3c2410fb_display) * npd->num_displays, + GFP_KERNEL); + if (!npd->displays) + printk(KERN_ERR "no memory for LCD display data\n"); + } else { + printk(KERN_ERR "no memory for LCD platform data\n"); + } +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* MIPI CSIS */ + +#ifdef CONFIG_S5P_DEV_CSIS0 +static struct resource s5p_mipi_csis0_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0), +}; + +struct platform_device s5p_device_mipi_csis0 = { + .name = "s5p-mipi-csis", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_mipi_csis0_resource), + .resource = s5p_mipi_csis0_resource, +}; +#endif /* CONFIG_S5P_DEV_CSIS0 */ + +#ifdef CONFIG_S5P_DEV_CSIS1 +static struct resource s5p_mipi_csis1_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1), +}; + +struct platform_device s5p_device_mipi_csis1 = { + .name = "s5p-mipi-csis", + .id = 1, + .num_resources = ARRAY_SIZE(s5p_mipi_csis1_resource), + .resource = s5p_mipi_csis1_resource, +}; +#endif + +/* NAND */ + +#ifdef CONFIG_S3C_DEV_NAND +static struct resource s3c_nand_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_NAND, SZ_1M), +}; + +struct platform_device s3c_device_nand = { + .name = "s3c2410-nand", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_nand_resource), + .resource = s3c_nand_resource, +}; + +/* + * s3c_nand_copy_set() - copy nand set data + * @set: The new structure, directly copied from the old. + * + * Copy all the fields from the NAND set field from what is probably __initdata + * to new kernel memory. The code returns 0 if the copy happened correctly or + * an error code for the calling function to display. + * + * Note, we currently do not try and look to see if we've already copied the + * data in a previous set. + */ +static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set) +{ + void *ptr; + int size; + + size = sizeof(struct mtd_partition) * set->nr_partitions; + if (size) { + ptr = kmemdup(set->partitions, size, GFP_KERNEL); + set->partitions = ptr; + + if (!ptr) + return -ENOMEM; + } + + if (set->nr_map && set->nr_chips) { + size = sizeof(int) * set->nr_chips; + ptr = kmemdup(set->nr_map, size, GFP_KERNEL); + set->nr_map = ptr; + + if (!ptr) + return -ENOMEM; + } + + if (set->ecc_layout) { + ptr = kmemdup(set->ecc_layout, + sizeof(struct nand_ecclayout), GFP_KERNEL); + set->ecc_layout = ptr; + + if (!ptr) + return -ENOMEM; + } + + return 0; +} + +void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand) +{ + struct s3c2410_platform_nand *npd; + int size; + int ret; + + /* 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. + */ + + npd = s3c_set_platdata(nand, sizeof(struct s3c2410_platform_nand), + &s3c_device_nand); + if (!npd) + return; + + /* now see if we need to copy any of the nand set data */ + + size = sizeof(struct s3c2410_nand_set) * npd->nr_sets; + if (size) { + struct s3c2410_nand_set *from = npd->sets; + struct s3c2410_nand_set *to; + int i; + + to = kmemdup(from, size, GFP_KERNEL); + npd->sets = to; /* set, even if we failed */ + + if (!to) { + printk(KERN_ERR "%s: no memory for sets\n", __func__); + return; + } + + for (i = 0; i < npd->nr_sets; i++) { + ret = s3c_nand_copy_set(to); + if (ret) { + printk(KERN_ERR "%s: failed to copy set %d\n", + __func__, i); + return; + } + to++; + } + } +} +#endif /* CONFIG_S3C_DEV_NAND */ + +/* ONENAND */ + +#ifdef CONFIG_S3C_DEV_ONENAND +static struct resource s3c_onenand_resources[] = { + [0] = DEFINE_RES_MEM(S3C_PA_ONENAND, SZ_1K), + [1] = DEFINE_RES_MEM(S3C_PA_ONENAND_BUF, S3C_SZ_ONENAND_BUF), + [2] = DEFINE_RES_IRQ(IRQ_ONENAND), +}; + +struct platform_device s3c_device_onenand = { + .name = "samsung-onenand", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_onenand_resources), + .resource = s3c_onenand_resources, +}; +#endif /* CONFIG_S3C_DEV_ONENAND */ + +#ifdef CONFIG_S3C64XX_DEV_ONENAND1 +static struct resource s3c64xx_onenand1_resources[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1, SZ_1K), + [1] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1_BUF, S3C64XX_SZ_ONENAND1_BUF), + [2] = DEFINE_RES_IRQ(IRQ_ONENAND1), +}; + +struct platform_device s3c64xx_device_onenand1 = { + .name = "samsung-onenand", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_onenand1_resources), + .resource = s3c64xx_onenand1_resources, +}; + +void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct onenand_platform_data), + &s3c64xx_device_onenand1); +} +#endif /* CONFIG_S3C64XX_DEV_ONENAND1 */ + +#ifdef CONFIG_S5P_DEV_ONENAND +static struct resource s5p_onenand_resources[] = { + [0] = DEFINE_RES_MEM(S5P_PA_ONENAND, SZ_128K), + [1] = DEFINE_RES_MEM(S5P_PA_ONENAND_DMA, SZ_8K), + [2] = DEFINE_RES_IRQ(IRQ_ONENAND_AUDI), +}; + +struct platform_device s5p_device_onenand = { + .name = "s5pc110-onenand", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_onenand_resources), + .resource = s5p_onenand_resources, +}; +#endif /* CONFIG_S5P_DEV_ONENAND */ + +/* PMU */ + +#if defined(CONFIG_PLAT_S5P) && !defined(CONFIG_ARCH_EXYNOS) +static struct resource s5p_pmu_resource[] = { + DEFINE_RES_IRQ(IRQ_PMU) +}; + +static struct platform_device s5p_device_pmu = { + .name = "arm-pmu", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_pmu_resource), + .resource = s5p_pmu_resource, +}; + +static int __init s5p_pmu_init(void) +{ + platform_device_register(&s5p_device_pmu); + return 0; +} +arch_initcall(s5p_pmu_init); +#endif /* CONFIG_PLAT_S5P */ + +/* PWM Timer */ + +#ifdef CONFIG_SAMSUNG_DEV_PWM +static struct resource samsung_pwm_resource[] = { + DEFINE_RES_MEM(SAMSUNG_PA_TIMER, SZ_4K), +}; + +struct platform_device samsung_device_pwm = { + .name = "samsung-pwm", + .id = -1, + .num_resources = ARRAY_SIZE(samsung_pwm_resource), + .resource = samsung_pwm_resource, +}; + +void __init samsung_pwm_set_platdata(struct samsung_pwm_variant *pd) +{ + samsung_device_pwm.dev.platform_data = pd; +} +#endif /* CONFIG_SAMSUNG_DEV_PWM */ + +/* RTC */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_rtc_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_RTC), + [2] = DEFINE_RES_IRQ(IRQ_TICK), +}; + +struct platform_device s3c_device_rtc = { + .name = "s3c2410-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +#ifdef CONFIG_S3C_DEV_RTC +static struct resource s3c_rtc_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_RTC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_RTC_ALARM), + [2] = DEFINE_RES_IRQ(IRQ_RTC_TIC), +}; + +struct platform_device s3c_device_rtc = { + .name = "s3c64xx-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; +#endif /* CONFIG_S3C_DEV_RTC */ + +/* SDI */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_sdi_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI), + [1] = DEFINE_RES_IRQ(IRQ_SDI), +}; + +struct platform_device s3c_device_sdi = { + .name = "s3c2410-sdi", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_sdi_resource), + .resource = s3c_sdi_resource, +}; + +void __init s3c24xx_mci_set_platdata(struct s3c24xx_mci_pdata *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct s3c24xx_mci_pdata), + &s3c_device_sdi); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* SPI */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_spi0_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SPI, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_SPI0), +}; + +struct platform_device s3c_device_spi0 = { + .name = "s3c2410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_spi0_resource), + .resource = s3c_spi0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +static struct resource s3c_spi1_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SPI1, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_SPI1), +}; + +struct platform_device s3c_device_spi1 = { + .name = "s3c2410-spi", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_spi1_resource), + .resource = s3c_spi1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +/* Touchscreen */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_ts_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), + [1] = DEFINE_RES_IRQ(IRQ_TC), +}; + +struct platform_device s3c_device_ts = { + .name = "s3c2410-ts", + .id = -1, + .dev.parent = &s3c_device_adc.dev, + .num_resources = ARRAY_SIZE(s3c_ts_resource), + .resource = s3c_ts_resource, +}; + +void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_info) +{ + s3c_set_platdata(hard_s3c2410ts_info, + sizeof(struct s3c2410_ts_mach_info), &s3c_device_ts); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +#ifdef CONFIG_SAMSUNG_DEV_TS +static struct resource s3c_ts_resource[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_TC), +}; + +static struct s3c2410_ts_mach_info default_ts_data __initdata = { + .delay = 10000, + .presc = 49, + .oversampling_shift = 2, +}; + +struct platform_device s3c_device_ts = { + .name = "s3c64xx-ts", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_ts_resource), + .resource = s3c_ts_resource, +}; + +void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd) +{ + if (!pd) + pd = &default_ts_data; + + s3c_set_platdata(pd, sizeof(struct s3c2410_ts_mach_info), + &s3c_device_ts); +} +#endif /* CONFIG_SAMSUNG_DEV_TS */ + +/* TV */ + +#ifdef CONFIG_S5P_DEV_TV + +static struct resource s5p_hdmi_resources[] = { + [0] = DEFINE_RES_MEM(S5P_PA_HDMI, SZ_1M), + [1] = DEFINE_RES_IRQ(IRQ_HDMI), +}; + +struct platform_device s5p_device_hdmi = { + .name = "s5p-hdmi", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_hdmi_resources), + .resource = s5p_hdmi_resources, +}; + +static struct resource s5p_sdo_resources[] = { + [0] = DEFINE_RES_MEM(S5P_PA_SDO, SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_SDO), +}; + +struct platform_device s5p_device_sdo = { + .name = "s5p-sdo", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_sdo_resources), + .resource = s5p_sdo_resources, +}; + +static struct resource s5p_mixer_resources[] = { + [0] = DEFINE_RES_MEM_NAMED(S5P_PA_MIXER, SZ_64K, "mxr"), + [1] = DEFINE_RES_MEM_NAMED(S5P_PA_VP, SZ_64K, "vp"), + [2] = DEFINE_RES_IRQ_NAMED(IRQ_MIXER, "irq"), +}; + +struct platform_device s5p_device_mixer = { + .name = "s5p-mixer", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_mixer_resources), + .resource = s5p_mixer_resources, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_S5P_DEV_TV */ + +/* USB */ + +#ifdef CONFIG_S3C_DEV_USB_HOST +static struct resource s3c_usb_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_USBHOST, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_USBH), +}; + +struct platform_device s3c_device_ohci = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +/* + * s3c_ohci_set_platdata - initialise OHCI device platform data + * @info: The platform data. + * + * This call copies the @info passed in and sets the device .platform_data + * field to that copy. The @info is copied so that the original can be marked + * __initdata. + */ + +void __init s3c_ohci_set_platdata(struct s3c2410_hcd_info *info) +{ + s3c_set_platdata(info, sizeof(struct s3c2410_hcd_info), + &s3c_device_ohci); +} +#endif /* CONFIG_S3C_DEV_USB_HOST */ + +/* USB Device (Gadget) */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_usbgadget_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_USBDEV, S3C24XX_SZ_USBDEV), + [1] = DEFINE_RES_IRQ(IRQ_USBD), +}; + +struct platform_device s3c_device_usbgadget = { + .name = "s3c2410-usbgadget", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usbgadget_resource), + .resource = s3c_usbgadget_resource, +}; + +void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd) +{ + s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usbgadget); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* USB HSOTG */ + +#ifdef CONFIG_S3C_DEV_USB_HSOTG +static struct resource s3c_usb_hsotg_resources[] = { + [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_128K), + [1] = DEFINE_RES_IRQ(IRQ_OTG), +}; + +struct platform_device s3c_device_usb_hsotg = { + .name = "s3c-hsotg", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_hsotg_resources), + .resource = s3c_usb_hsotg_resources, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd) +{ + struct s3c_hsotg_plat *npd; + + npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat), + &s3c_device_usb_hsotg); + + if (!npd->phy_init) + npd->phy_init = s5p_usb_phy_init; + if (!npd->phy_exit) + npd->phy_exit = s5p_usb_phy_exit; +} +#endif /* CONFIG_S3C_DEV_USB_HSOTG */ + +/* USB High Spped 2.0 Device (Gadget) */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_hsudc_resource[] = { + [0] = DEFINE_RES_MEM(S3C2416_PA_HSUDC, S3C2416_SZ_HSUDC), + [1] = DEFINE_RES_IRQ(IRQ_USBD), +}; + +struct platform_device s3c_device_usb_hsudc = { + .name = "s3c-hsudc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_hsudc_resource), + .resource = s3c_hsudc_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd) +{ + s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usb_hsudc); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* WDT */ + +#ifdef CONFIG_S3C_DEV_WDT +static struct resource s3c_wdt_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_WDT, SZ_1K), + [1] = DEFINE_RES_IRQ(IRQ_WDT), +}; + +struct platform_device s3c_device_wdt = { + .name = "s3c2410-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_wdt_resource), + .resource = s3c_wdt_resource, +}; +#endif /* CONFIG_S3C_DEV_WDT */ + +#ifdef CONFIG_S3C64XX_DEV_SPI0 +static struct resource s3c64xx_spi0_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_SPI0, SZ_256), + [1] = DEFINE_RES_DMA(DMACH_SPI0_TX), + [2] = DEFINE_RES_DMA(DMACH_SPI0_RX), + [3] = DEFINE_RES_IRQ(IRQ_SPI0), +}; + +struct platform_device s3c64xx_device_spi0 = { + .name = "s3c6410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c64xx_spi0_resource), + .resource = s3c64xx_spi0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, + int num_cs) +{ + struct s3c64xx_spi_info pd; + + /* Reject invalid configuration */ + if (!num_cs || src_clk_nr < 0) { + pr_err("%s: Invalid SPI configuration\n", __func__); + return; + } + + pd.num_cs = num_cs; + pd.src_clk_nr = src_clk_nr; + pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio; +#if defined(CONFIG_PL330_DMA) + pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; +#elif defined(CONFIG_S3C24XX_DMAC) + pd.filter = s3c24xx_dma_filter; +#endif + + s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0); +} +#endif /* CONFIG_S3C64XX_DEV_SPI0 */ + +#ifdef CONFIG_S3C64XX_DEV_SPI1 +static struct resource s3c64xx_spi1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_SPI1, SZ_256), + [1] = DEFINE_RES_DMA(DMACH_SPI1_TX), + [2] = DEFINE_RES_DMA(DMACH_SPI1_RX), + [3] = DEFINE_RES_IRQ(IRQ_SPI1), +}; + +struct platform_device s3c64xx_device_spi1 = { + .name = "s3c6410-spi", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_spi1_resource), + .resource = s3c64xx_spi1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, + int num_cs) +{ + struct s3c64xx_spi_info pd; + + /* Reject invalid configuration */ + if (!num_cs || src_clk_nr < 0) { + pr_err("%s: Invalid SPI configuration\n", __func__); + return; + } + + pd.num_cs = num_cs; + pd.src_clk_nr = src_clk_nr; + pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; +#if defined(CONFIG_PL330_DMA) + pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; +#endif + + s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); +} +#endif /* CONFIG_S3C64XX_DEV_SPI1 */ + +#ifdef CONFIG_S3C64XX_DEV_SPI2 +static struct resource s3c64xx_spi2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_SPI2, SZ_256), + [1] = DEFINE_RES_DMA(DMACH_SPI2_TX), + [2] = DEFINE_RES_DMA(DMACH_SPI2_RX), + [3] = DEFINE_RES_IRQ(IRQ_SPI2), +}; + +struct platform_device s3c64xx_device_spi2 = { + .name = "s3c6410-spi", + .id = 2, + .num_resources = ARRAY_SIZE(s3c64xx_spi2_resource), + .resource = s3c64xx_spi2_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, + int num_cs) +{ + struct s3c64xx_spi_info pd; + + /* Reject invalid configuration */ + if (!num_cs || src_clk_nr < 0) { + pr_err("%s: Invalid SPI configuration\n", __func__); + return; + } + + pd.num_cs = num_cs; + pd.src_clk_nr = src_clk_nr; + pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; +#if defined(CONFIG_PL330_DMA) + pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; +#endif + + s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); +} +#endif /* CONFIG_S3C64XX_DEV_SPI2 */ diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c new file mode 100644 index 00000000000..886326ee6f6 --- /dev/null +++ b/arch/arm/plat-samsung/dma-ops.c @@ -0,0 +1,146 @@ +/* linux/arch/arm/plat-samsung/dma-ops.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung DMA Operations + * + * 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/errno.h> +#include <linux/amba/pl330.h> +#include <linux/scatterlist.h> +#include <linux/export.h> + +#include <mach/dma.h> + +#if defined(CONFIG_PL330_DMA) +#define dma_filter pl330_filter +#elif defined(CONFIG_S3C64XX_PL080) +#define dma_filter pl08x_filter_id +#endif + +static unsigned samsung_dmadev_request(enum dma_ch dma_ch, + struct samsung_dma_req *param, + struct device *dev, char *ch_name) +{ + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(param->cap, mask); + + if (dev->of_node) + return (unsigned)dma_request_slave_channel(dev, ch_name); + else + return (unsigned)dma_request_channel(mask, dma_filter, + (void *)dma_ch); +} + +static int samsung_dmadev_release(unsigned ch, void *param) +{ + dma_release_channel((struct dma_chan *)ch); + + return 0; +} + +static int samsung_dmadev_config(unsigned ch, + struct samsung_dma_config *param) +{ + struct dma_chan *chan = (struct dma_chan *)ch; + struct dma_slave_config slave_config; + + if (param->direction == DMA_DEV_TO_MEM) { + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + slave_config.direction = param->direction; + slave_config.src_addr = param->fifo; + slave_config.src_addr_width = param->width; + slave_config.src_maxburst = 1; + dmaengine_slave_config(chan, &slave_config); + } else if (param->direction == DMA_MEM_TO_DEV) { + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + slave_config.direction = param->direction; + slave_config.dst_addr = param->fifo; + slave_config.dst_addr_width = param->width; + slave_config.dst_maxburst = 1; + dmaengine_slave_config(chan, &slave_config); + } else { + pr_warn("unsupported direction\n"); + return -EINVAL; + } + + return 0; +} + +static int samsung_dmadev_prepare(unsigned ch, + struct samsung_dma_prep *param) +{ + struct scatterlist sg; + struct dma_chan *chan = (struct dma_chan *)ch; + struct dma_async_tx_descriptor *desc; + + switch (param->cap) { + case DMA_SLAVE: + sg_init_table(&sg, 1); + sg_dma_len(&sg) = param->len; + sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)), + param->len, offset_in_page(param->buf)); + sg_dma_address(&sg) = param->buf; + + desc = dmaengine_prep_slave_sg(chan, + &sg, 1, param->direction, DMA_PREP_INTERRUPT); + break; + case DMA_CYCLIC: + desc = dmaengine_prep_dma_cyclic(chan, param->buf, + param->len, param->period, param->direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + break; + default: + dev_err(&chan->dev->device, "unsupported format\n"); + return -EFAULT; + } + + if (!desc) { + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + return -EFAULT; + } + + desc->callback = param->fp; + desc->callback_param = param->fp_param; + + dmaengine_submit((struct dma_async_tx_descriptor *)desc); + + return 0; +} + +static inline int samsung_dmadev_trigger(unsigned ch) +{ + dma_async_issue_pending((struct dma_chan *)ch); + + return 0; +} + +static inline int samsung_dmadev_flush(unsigned ch) +{ + return dmaengine_terminate_all((struct dma_chan *)ch); +} + +static struct samsung_dma_ops dmadev_ops = { + .request = samsung_dmadev_request, + .release = samsung_dmadev_release, + .config = samsung_dmadev_config, + .prepare = samsung_dmadev_prepare, + .trigger = samsung_dmadev_trigger, + .started = NULL, + .flush = samsung_dmadev_flush, + .stop = samsung_dmadev_flush, +}; + +void *samsung_dmadev_get_ops(void) +{ + return &dmadev_ops; +} +EXPORT_SYMBOL(samsung_dmadev_get_ops); diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c new file mode 100644 index 00000000000..6143aa14768 --- /dev/null +++ b/arch/arm/plat-samsung/dma.c @@ -0,0 +1,84 @@ +/* linux/arch/arm/plat-samsung/dma.c + * + * Copyright (c) 2003-2009 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C DMA core + * + * 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. +*/ + +struct s3c2410_dma_buf; + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> + +#include <mach/dma.h> +#include <mach/irqs.h> + +/* dma channel state information */ +struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; +struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX]; + +/* s3c_dma_lookup_channel + * + * change the dma channel number given into a real dma channel id +*/ + +struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel) +{ + if (channel & DMACH_LOW_LEVEL) + return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; + else + return s3c_dma_chan_map[channel]; +} + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(enum dma_ch channel, s3c2410_dma_opfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_opfn); + +int s3c2410_dma_set_buffdone_fn(enum dma_ch channel, s3c2410_dma_cbfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); + +int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + chan->flags = flags; + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_setflags); diff --git a/arch/arm/plat-samsung/include/plat/adc-core.h b/arch/arm/plat-samsung/include/plat/adc-core.h new file mode 100644 index 00000000000..a927bee5535 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/adc-core.h @@ -0,0 +1,28 @@ +/* linux/arch/arm/plat-samsung/include/plat/adc-core.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Samsung ADC Controller core functions + * + * 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 __ASM_PLAT_ADC_CORE_H +#define __ASM_PLAT_ADC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_adc_setname(char *name) +{ +#if defined(CONFIG_SAMSUNG_DEV_ADC) || defined(CONFIG_PLAT_S3C24XX) + s3c_device_adc.name = name; +#endif +} + +#endif /* __ASM_PLAT_ADC_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/adc.h b/arch/arm/plat-samsung/include/plat/adc.h new file mode 100644 index 00000000000..2fc89315553 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/adc.h @@ -0,0 +1,36 @@ +/* arch/arm/plat-samsung/include/plat/adc.h + * + * Copyright (c) 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C ADC driver information + * + * 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 __ASM_PLAT_ADC_H +#define __ASM_PLAT_ADC_H __FILE__ + +struct s3c_adc_client; +struct platform_device; + +extern int s3c_adc_start(struct s3c_adc_client *client, + unsigned int channel, unsigned int nr_samples); + +extern int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch); + +extern struct s3c_adc_client * + s3c_adc_register(struct platform_device *pdev, + void (*select)(struct s3c_adc_client *client, + unsigned selected), + void (*conv)(struct s3c_adc_client *client, + unsigned d0, unsigned d1, + unsigned *samples_left), + unsigned int is_ts); + +extern void s3c_adc_release(struct s3c_adc_client *client); + +#endif /* __ASM_PLAT_ADC_H */ diff --git a/arch/arm/plat-samsung/include/plat/ata-core.h b/arch/arm/plat-samsung/include/plat/ata-core.h new file mode 100644 index 00000000000..f5a4ec7141b --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/ata-core.h @@ -0,0 +1,28 @@ +/* linux/arch/arm/plat-samsung/include/plat/ata-core.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CF-ATA Controller core functions + * + * 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 __ASM_PLAT_ATA_CORE_H +#define __ASM_PLAT_ATA_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code +*/ + +/* re-define device name depending on support. */ +static inline void s3c_cfcon_setname(char *name) +{ +#ifdef CONFIG_SAMSUNG_DEV_IDE + s3c_device_cfcon.name = name; +#endif +} + +#endif /* __ASM_PLAT_ATA_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/backlight.h b/arch/arm/plat-samsung/include/plat/backlight.h new file mode 100644 index 00000000000..ad530c78fe8 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/backlight.h @@ -0,0 +1,26 @@ +/* linux/arch/arm/plat-samsung/include/plat/backlight.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.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. + */ + +#ifndef __ASM_PLAT_BACKLIGHT_H +#define __ASM_PLAT_BACKLIGHT_H __FILE__ + +/* samsung_bl_gpio_info - GPIO info for PWM Backlight control + * @no: GPIO number for PWM timer out + * @func: Special function of GPIO line for PWM timer + */ +struct samsung_bl_gpio_info { + int no; + int func; +}; + +extern void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, + struct platform_pwm_backlight_data *bl_data); + +#endif /* __ASM_PLAT_BACKLIGHT_H */ diff --git a/arch/arm/plat-samsung/include/plat/camport.h b/arch/arm/plat-samsung/include/plat/camport.h new file mode 100644 index 00000000000..a5708bf84b3 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/camport.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * S5P series camera interface helper functions + * + * 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 __PLAT_SAMSUNG_CAMPORT_H_ +#define __PLAT_SAMSUNG_CAMPORT_H_ __FILE__ + +enum s5p_camport_id { + S5P_CAMPORT_A, + S5P_CAMPORT_B, +}; + +/* + * The helper functions to configure GPIO for the camera parallel bus. + * The camera port can be multiplexed with any FIMC entity, even multiple + * FIMC entities are allowed to be attached to a single port simultaneously. + * These functions are to be used in the board setup code. + */ +int s5pv210_fimc_setup_gpio(enum s5p_camport_id id); +int exynos4_fimc_setup_gpio(enum s5p_camport_id id); + +#endif /* __PLAT_SAMSUNG_CAMPORT_H */ diff --git a/arch/arm/plat-samsung/include/plat/clock-clksrc.h b/arch/arm/plat-samsung/include/plat/clock-clksrc.h new file mode 100644 index 00000000000..50a8ca7c376 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/clock-clksrc.h @@ -0,0 +1,83 @@ +/* linux/arch/arm/plat-samsung/include/plat/clock-clksrc.h + * + * Parts taken from arch/arm/plat-s3c64xx/clock.c + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Copyright 2009 Ben Dooks <ben-linux@fluff.org> + * Copyright 2009 Harald Welte + * + * 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. +*/ + +/** + * struct clksrc_sources - list of sources for a given clock + * @sources: array of pointers to clocks + * @nr_sources: The size of @sources + */ +struct clksrc_sources { + unsigned int nr_sources; + struct clk **sources; +}; + +/** + * struct clksrc_reg - register definition for clock control bits + * @reg: pointer to the register in virtual memory. + * @shift: the shift in bits to where the bitfield is. + * @size: the size in bits of the bitfield. + * + * This specifies the size and position of the bits we are interested + * in within the register specified by @reg. + */ +struct clksrc_reg { + void __iomem *reg; + unsigned short shift; + unsigned short size; +}; + +/** + * struct clksrc_clk - class of clock for newer style samsung devices. + * @clk: the standard clock representation + * @sources: the sources for this clock + * @reg_src: the register definition for selecting the clock's source + * @reg_div: the register definition for the clock's output divisor + * + * This clock implements the features required by the newer SoCs where + * the standard clock block provides an input mux and a post-mux divisor + * to provide the periperhal's clock. + * + * The array of @sources provides the mapping of mux position to the + * clock, and @reg_src shows the code where to modify to change the mux + * position. The @reg_div defines how to change the divider settings on + * the output. + */ +struct clksrc_clk { + struct clk clk; + struct clksrc_sources *sources; + + struct clksrc_reg reg_src; + struct clksrc_reg reg_div; +}; + +/** + * s3c_set_clksrc() - setup the clock from the register settings + * @clk: The clock to setup. + * @announce: true to announce the setting to printk(). + * + * Setup the clock from the current register settings, for when the + * kernel boots or if it is resuming from a possibly unknown state. + */ +extern void s3c_set_clksrc(struct clksrc_clk *clk, bool announce); + +/** + * s3c_register_clksrc() register clocks from an array of clksrc clocks + * @srcs: The array of clocks to register + * @size: The size of the @srcs array. + * + * Initialise and register the array of clocks described by @srcs. + */ +extern void s3c_register_clksrc(struct clksrc_clk *srcs, int size); diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h new file mode 100644 index 00000000000..63239f40980 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/clock.h @@ -0,0 +1,152 @@ +/* linux/arch/arm/plat-s3c/include/plat/clock.h + * + * Copyright (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Written by Ben Dooks, <ben@simtec.co.uk> + * + * 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 __ASM_PLAT_CLOCK_H +#define __ASM_PLAT_CLOCK_H __FILE__ + +#include <linux/spinlock.h> +#include <linux/clkdev.h> + +struct clk; + +/** + * struct clk_ops - standard clock operations + * @set_rate: set the clock rate, see clk_set_rate(). + * @get_rate: get the clock rate, see clk_get_rate(). + * @round_rate: round a given clock rate, see clk_round_rate(). + * @set_parent: set the clock's parent, see clk_set_parent(). + * + * Group the common clock implementations together so that we + * don't have to keep setting the same fields again. We leave + * enable in struct clk. + * + * Adding an extra layer of indirection into the process should + * not be a problem as it is unlikely these operations are going + * to need to be called quickly. + */ +struct clk_ops { + int (*set_rate)(struct clk *c, unsigned long rate); + unsigned long (*get_rate)(struct clk *c); + unsigned long (*round_rate)(struct clk *c, unsigned long rate); + int (*set_parent)(struct clk *c, struct clk *parent); +}; + +struct clk { + struct list_head list; + struct module *owner; + struct clk *parent; + const char *name; + const char *devname; + int id; + int usage; + unsigned long rate; + unsigned long ctrlbit; + + struct clk_ops *ops; + int (*enable)(struct clk *, int enable); + struct clk_lookup lookup; +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) + struct dentry *dent; /* For visible tree hierarchy */ +#endif +}; + +/* other clocks which may be registered by board support */ + +extern struct clk s3c24xx_dclk0; +extern struct clk s3c24xx_dclk1; +extern struct clk s3c24xx_clkout0; +extern struct clk s3c24xx_clkout1; +extern struct clk s3c24xx_uclk; + +extern struct clk clk_usb_bus; + +/* core clock support */ + +extern struct clk clk_f; +extern struct clk clk_h; +extern struct clk clk_p; +extern struct clk clk_mpll; +extern struct clk clk_upll; +extern struct clk clk_epll; +extern struct clk clk_xtal; +extern struct clk clk_ext; + +/* S3C2443/S3C2416 specific clocks */ +extern struct clksrc_clk clk_epllref; +extern struct clksrc_clk clk_esysclk; + +/* S3C24XX UART clocks */ +extern struct clk s3c24xx_clk_uart0; +extern struct clk s3c24xx_clk_uart1; +extern struct clk s3c24xx_clk_uart2; + +/* S3C64XX specific clocks */ +extern struct clk clk_h2; +extern struct clk clk_27m; +extern struct clk clk_48m; +extern struct clk clk_xusbxti; + +extern int clk_default_setrate(struct clk *clk, unsigned long rate); +extern struct clk_ops clk_ops_def_setrate; + +/* exports for arch/arm/mach-s3c2410 + * + * Please DO NOT use these outside of arch/arm/mach-s3c2410 +*/ + +extern spinlock_t clocks_lock; + +extern int s3c2410_clkcon_enable(struct clk *clk, int enable); + +extern int s3c24xx_register_clock(struct clk *clk); +extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks); + +extern void s3c_register_clocks(struct clk *clk, int nr_clks); +extern void s3c_disable_clocks(struct clk *clkp, int nr_clks); + +extern int s3c24xx_register_baseclocks(unsigned long xtal); + +extern void s5p_register_clocks(unsigned long xtal_freq); + +extern void s3c24xx_setup_clocks(unsigned long fclk, + unsigned long hclk, + unsigned long pclk); + +extern void s3c2410_setup_clocks(void); +extern void s3c2412_setup_clocks(void); +extern void s3c244x_setup_clocks(void); + +/* S3C2410 specific clock functions */ + +extern int s3c2410_baseclk_add(void); + +/* S3C2443/S3C2416 specific clock functions */ + +typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base); + +extern void s3c2443_common_setup_clocks(pll_fn get_mpll); +extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, + unsigned int *divs, int nr_divs, + int divmask); + +extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable); +extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable); +extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable); + +/* S3C64XX specific functions and clocks */ + +extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable); + +/* Global watchdog clock used by arch_wtd_reset() callback */ + +extern struct clk *s3c2410_wdtclk; + +#endif /* __ASM_PLAT_CLOCK_H */ diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq-core.h b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h new file mode 100644 index 00000000000..72d4178ad23 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h @@ -0,0 +1,294 @@ +/* arch/arm/plat-samsung/include/plat/cpu-freq-core.h + * + * Copyright (c) 2006-2009 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C CPU frequency scaling support - core support + * + * 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 <plat/cpu-freq.h> + +struct seq_file; + +#define MAX_BANKS (8) +#define S3C2412_MAX_IO (8) + +/** + * struct s3c2410_iobank_timing - IO bank timings for S3C2410 style timings + * @bankcon: The cached version of settings in this structure. + * @tacp: + * @tacs: Time from address valid to nCS asserted. + * @tcos: Time from nCS asserted to nOE or nWE asserted. + * @tacc: Time that nOE or nWE is asserted. + * @tcoh: Time nCS is held after nOE or nWE are released. + * @tcah: Time address is held for after + * @nwait_en: Whether nWAIT is enabled for this bank. + * + * This structure represents the IO timings for a S3C2410 style IO bank + * used by the CPU frequency support if it needs to change the settings + * of the IO. + */ +struct s3c2410_iobank_timing { + unsigned long bankcon; + unsigned int tacp; + unsigned int tacs; + unsigned int tcos; + unsigned int tacc; + unsigned int tcoh; /* nCS hold afrer nOE/nWE */ + unsigned int tcah; /* Address hold after nCS */ + unsigned char nwait_en; /* nWait enabled for bank. */ +}; + +/** + * struct s3c2412_iobank_timing - io timings for PL092 (S3C2412) style IO + * @idcy: The idle cycle time between transactions. + * @wstrd: nCS release to end of read cycle. + * @wstwr: nCS release to end of write cycle. + * @wstoen: nCS assertion to nOE assertion time. + * @wstwen: nCS assertion to nWE assertion time. + * @wstbrd: Burst ready delay. + * @smbidcyr: Register cache for smbidcyr value. + * @smbwstrd: Register cache for smbwstrd value. + * @smbwstwr: Register cache for smbwstwr value. + * @smbwstoen: Register cache for smbwstoen value. + * @smbwstwen: Register cache for smbwstwen value. + * @smbwstbrd: Register cache for smbwstbrd value. + * + * Timing information for a IO bank on an S3C2412 or similar system which + * uses a PL093 block. + */ +struct s3c2412_iobank_timing { + unsigned int idcy; + unsigned int wstrd; + unsigned int wstwr; + unsigned int wstoen; + unsigned int wstwen; + unsigned int wstbrd; + + /* register cache */ + unsigned char smbidcyr; + unsigned char smbwstrd; + unsigned char smbwstwr; + unsigned char smbwstoen; + unsigned char smbwstwen; + unsigned char smbwstbrd; +}; + +union s3c_iobank { + struct s3c2410_iobank_timing *io_2410; + struct s3c2412_iobank_timing *io_2412; +}; + +/** + * struct s3c_iotimings - Chip IO timings holder + * @bank: The timings for each IO bank. + */ +struct s3c_iotimings { + union s3c_iobank bank[MAX_BANKS]; +}; + +/** + * struct s3c_plltab - PLL table information. + * @vals: List of PLL values. + * @size: Size of the PLL table @vals. + */ +struct s3c_plltab { + struct s3c_pllval *vals; + int size; +}; + +/** + * struct s3c_cpufreq_config - current cpu frequency configuration + * @freq: The current settings for the core clocks. + * @max: Maxium settings, derived from core, board and user settings. + * @pll: The PLL table entry for the current PLL settings. + * @divs: The divisor settings for the core clocks. + * @info: The current core driver information. + * @board: The information for the board we are running on. + * @lock_pll: Set if the PLL settings cannot be changed. + * + * This is for the core drivers that need to know information about + * the current settings and values. It should not be needed by any + * device drivers. +*/ +struct s3c_cpufreq_config { + struct s3c_freq freq; + struct s3c_freq max; + struct clk *mpll; + struct cpufreq_frequency_table pll; + struct s3c_clkdivs divs; + struct s3c_cpufreq_info *info; /* for core, not drivers */ + struct s3c_cpufreq_board *board; + + unsigned int lock_pll:1; +}; + +/** + * struct s3c_cpufreq_info - Information for the CPU frequency driver. + * @name: The name of this implementation. + * @max: The maximum frequencies for the system. + * @latency: Transition latency to give to cpufreq. + * @locktime_m: The lock-time in uS for the MPLL. + * @locktime_u: The lock-time in uS for the UPLL. + * @locttime_bits: The number of bits each LOCKTIME field. + * @need_pll: Set if this driver needs to change the PLL values to achieve + * any frequency changes. This is really only need by devices like the + * S3C2410 where there is no or limited divider between the PLL and the + * ARMCLK. + * @resume_clocks: Update the clocks on resume. + * @get_iotiming: Get the current IO timing data, mainly for use at start. + * @set_iotiming: Update the IO timings from the cached copies calculated + * from the @calc_iotiming entry when changing the frequency. + * @calc_iotiming: Calculate and update the cached copies of the IO timings + * from the newly calculated frequencies. + * @calc_freqtable: Calculate (fill in) the given frequency table from the + * current frequency configuration. If the table passed in is NULL, + * then the return is the number of elements to be filled for allocation + * of the table. + * @set_refresh: Set the memory refresh configuration. + * @set_fvco: Set the PLL frequencies. + * @set_divs: Update the clock divisors. + * @calc_divs: Calculate the clock divisors. + */ +struct s3c_cpufreq_info { + const char *name; + struct s3c_freq max; + + unsigned int latency; + + unsigned int locktime_m; + unsigned int locktime_u; + unsigned char locktime_bits; + + unsigned int need_pll:1; + + /* driver routines */ + + void (*resume_clocks)(void); + + int (*get_iotiming)(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *timings); + + void (*set_iotiming)(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *timings); + + int (*calc_iotiming)(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *timings); + + int (*calc_freqtable)(struct s3c_cpufreq_config *cfg, + struct cpufreq_frequency_table *t, + size_t table_size); + + void (*debug_io_show)(struct seq_file *seq, + struct s3c_cpufreq_config *cfg, + union s3c_iobank *iob); + + void (*set_refresh)(struct s3c_cpufreq_config *cfg); + void (*set_fvco)(struct s3c_cpufreq_config *cfg); + void (*set_divs)(struct s3c_cpufreq_config *cfg); + int (*calc_divs)(struct s3c_cpufreq_config *cfg); +}; + +extern int s3c_cpufreq_register(struct s3c_cpufreq_info *info); + +extern int s3c_plltab_register(struct cpufreq_frequency_table *plls, + unsigned int plls_no); + +/* exports and utilities for debugfs */ +extern struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void); +extern struct s3c_iotimings *s3c_cpufreq_getiotimings(void); + +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS +#define s3c_cpufreq_debugfs_call(x) x +#else +#define s3c_cpufreq_debugfs_call(x) NULL +#endif + +/* Useful utility functions. */ + +extern struct clk *s3c_cpufreq_clk_get(struct device *, const char *); + +/* S3C2410 and compatible exported functions */ + +extern void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg); +extern void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg); + +#ifdef CONFIG_S3C2410_IOTIMING +extern void s3c2410_iotiming_debugfs(struct seq_file *seq, + struct s3c_cpufreq_config *cfg, + union s3c_iobank *iob); + +extern int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *iot); + +extern int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *timings); + +extern void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *iot); +#else +#define s3c2410_iotiming_debugfs NULL +#define s3c2410_iotiming_calc NULL +#define s3c2410_iotiming_get NULL +#define s3c2410_iotiming_set NULL +#endif /* CONFIG_S3C2410_IOTIMING */ + +/* S3C2412 compatible routines */ + +#ifdef CONFIG_S3C2412_IOTIMING +extern void s3c2412_iotiming_debugfs(struct seq_file *seq, + struct s3c_cpufreq_config *cfg, + union s3c_iobank *iob); + +extern int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *timings); + +extern int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *iot); + +extern void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg, + struct s3c_iotimings *iot); +#else +#define s3c2412_iotiming_debugfs NULL +#define s3c2412_iotiming_calc NULL +#define s3c2412_iotiming_get NULL +#define s3c2412_iotiming_set NULL +#endif /* CONFIG_S3C2412_IOTIMING */ + +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUG +#define s3c_freq_dbg(x...) printk(KERN_INFO x) +#else +#define s3c_freq_dbg(x...) do { if (0) printk(x); } while (0) +#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_DEBUG */ + +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_IODEBUG +#define s3c_freq_iodbg(x...) printk(KERN_INFO x) +#else +#define s3c_freq_iodbg(x...) do { if (0) printk(x); } while (0) +#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_IODEBUG */ + +static inline int s3c_cpufreq_addfreq(struct cpufreq_frequency_table *table, + int index, size_t table_size, + unsigned int freq) +{ + if (index < 0) + return index; + + if (table) { + if (index >= table_size) + return -ENOMEM; + + s3c_freq_dbg("%s: { %d = %u kHz }\n", + __func__, index, freq); + + table[index].driver_data = index; + table[index].frequency = freq; + } + + return index + 1; +} diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq.h b/arch/arm/plat-samsung/include/plat/cpu-freq.h new file mode 100644 index 00000000000..85517ab962a --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/cpu-freq.h @@ -0,0 +1,145 @@ +/* arch/arm/plat-samsung/include/plat/cpu-freq.h + * + * Copyright (c) 2006-2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C CPU frequency scaling support - driver and board + * + * 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/cpufreq.h> + +struct s3c_cpufreq_info; +struct s3c_cpufreq_board; +struct s3c_iotimings; + +/** + * struct s3c_freq - frequency information (mainly for core drivers) + * @fclk: The FCLK frequency in Hz. + * @armclk: The ARMCLK frequency in Hz. + * @hclk_tns: HCLK cycle time in 10ths of nano-seconds. + * @hclk: The HCLK frequency in Hz. + * @pclk: The PCLK frequency in Hz. + * + * This contains the frequency information about the current configuration + * mainly for the core drivers to ensure we do not end up passing about + * a large number of parameters. + * + * The @hclk_tns field is a useful cache for the parts of the drivers that + * need to calculate IO timings and suchlike. + */ +struct s3c_freq { + unsigned long fclk; + unsigned long armclk; + unsigned long hclk_tns; /* in 10ths of ns */ + unsigned long hclk; + unsigned long pclk; +}; + +/** + * struct s3c_cpufreq_freqs - s3c cpufreq notification information. + * @freqs: The cpufreq setting information. + * @old: The old clock settings. + * @new: The new clock settings. + * @pll_changing: Set if the PLL is changing. + * + * Wrapper 'struct cpufreq_freqs' so that any drivers receiving the + * notification can use this information that is not provided by just + * having the core frequency alone. + * + * The pll_changing flag is used to indicate if the PLL itself is + * being set during this change. This is important as the clocks + * will temporarily be set to the XTAL clock during this time, so + * drivers may want to close down their output during this time. + * + * Note, this is not being used by any current drivers and therefore + * may be removed in the future. + */ +struct s3c_cpufreq_freqs { + struct cpufreq_freqs freqs; + struct s3c_freq old; + struct s3c_freq new; + + unsigned int pll_changing:1; +}; + +#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs) + +/** + * struct s3c_clkdivs - clock divisor information + * @p_divisor: Divisor from FCLK to PCLK. + * @h_divisor: Divisor from FCLK to HCLK. + * @arm_divisor: Divisor from FCLK to ARMCLK (not all CPUs). + * @dvs: Non-zero if using DVS mode for ARMCLK. + * + * Divisor settings for the core clocks. + */ +struct s3c_clkdivs { + int p_divisor; + int h_divisor; + int arm_divisor; + unsigned char dvs; +}; + +#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s)) + +/** + * struct s3c_pllval - PLL value entry. + * @freq: The frequency for this entry in Hz. + * @pll_reg: The PLL register setting for this PLL value. + */ +struct s3c_pllval { + unsigned long freq; + unsigned long pll_reg; +}; + +/** + * struct s3c_cpufreq_board - per-board cpu frequency informatin + * @refresh: The SDRAM refresh period in nanoseconds. + * @auto_io: Set if the IO timing settings should be generated from the + * initialisation time hardware registers. + * @need_io: Set if the board has external IO on any of the chipselect + * lines that will require the hardware timing registers to be + * updated on a clock change. + * @max: The maxium frequency limits for the system. Any field that + * is left at zero will use the CPU's settings. + * + * This contains the board specific settings that affect how the CPU + * drivers chose settings. These include the memory refresh and IO + * timing information. + * + * Registration depends on the driver being used, the ARMCLK only + * implementation does not currently need this but the older style + * driver requires this to be available. + */ +struct s3c_cpufreq_board { + unsigned int refresh; + unsigned int auto_io:1; /* automatically init io timings. */ + unsigned int need_io:1; /* set if needs io timing support. */ + + /* any non-zero field in here is taken as an upper limit. */ + struct s3c_freq max; /* frequency limits */ +}; + +/* Things depending on frequency scaling. */ +#ifdef CONFIG_ARM_S3C_CPUFREQ +#define __init_or_cpufreq +#else +#define __init_or_cpufreq __init +#endif + +/* Board functions */ + +#ifdef CONFIG_ARM_S3C_CPUFREQ +extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board); +#else + +static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) +{ + return 0; +} +#endif /* CONFIG_ARM_S3C_CPUFREQ */ diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h new file mode 100644 index 00000000000..5a237db9f9e --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -0,0 +1,185 @@ +/* linux/arch/arm/plat-samsung/include/plat/cpu.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for Samsung CPU support + * + * 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. +*/ + +/* todo - fix when rmk changes iodescs to use `void __iomem *` */ + +#ifndef __SAMSUNG_PLAT_CPU_H +#define __SAMSUNG_PLAT_CPU_H + +extern unsigned long samsung_cpu_id; + +#define S3C2410_CPU_ID 0x32410000 +#define S3C2410_CPU_MASK 0xFFFFFFFF + +#define S3C24XX_CPU_ID 0x32400000 +#define S3C24XX_CPU_MASK 0xFFF00000 + +#define S3C2412_CPU_ID 0x32412000 +#define S3C2412_CPU_MASK 0xFFFFF000 + +#define S3C6400_CPU_ID 0x36400000 +#define S3C6410_CPU_ID 0x36410000 +#define S3C64XX_CPU_MASK 0xFFFFF000 + +#define S5P6440_CPU_ID 0x56440000 +#define S5P6450_CPU_ID 0x36450000 +#define S5P64XX_CPU_MASK 0xFFFFF000 + +#define S5PC100_CPU_ID 0x43100000 +#define S5PC100_CPU_MASK 0xFFFFF000 + +#define S5PV210_CPU_ID 0x43110000 +#define S5PV210_CPU_MASK 0xFFFFF000 + +#define IS_SAMSUNG_CPU(name, id, mask) \ +static inline int is_samsung_##name(void) \ +{ \ + return ((samsung_cpu_id & mask) == (id & mask)); \ +} + +IS_SAMSUNG_CPU(s3c2410, S3C2410_CPU_ID, S3C2410_CPU_MASK) +IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK) +IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c6410, S3C6410_CPU_ID, S3C64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5p6440, S5P6440_CPU_ID, S5P64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5p6450, S5P6450_CPU_ID, S5P64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5pc100, S5PC100_CPU_ID, S5PC100_CPU_MASK) +IS_SAMSUNG_CPU(s5pv210, S5PV210_CPU_ID, S5PV210_CPU_MASK) + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \ + defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2440) || \ + defined(CONFIG_CPU_S3C2442) || defined(CONFIG_CPU_S3C244X) || \ + defined(CONFIG_CPU_S3C2443) +# define soc_is_s3c24xx() is_samsung_s3c24xx() +# define soc_is_s3c2410() is_samsung_s3c2410() +#else +# define soc_is_s3c24xx() 0 +# define soc_is_s3c2410() 0 +#endif + +#if defined(CONFIG_CPU_S3C2412) +# define soc_is_s3c2412() is_samsung_s3c2412() +#else +# define soc_is_s3c2412() 0 +#endif + +#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) +# define soc_is_s3c6400() is_samsung_s3c6400() +# define soc_is_s3c6410() is_samsung_s3c6410() +# define soc_is_s3c64xx() (is_samsung_s3c6400() || is_samsung_s3c6410()) +#else +# define soc_is_s3c6400() 0 +# define soc_is_s3c6410() 0 +# define soc_is_s3c64xx() 0 +#endif + +#if defined(CONFIG_CPU_S5P6440) +# define soc_is_s5p6440() is_samsung_s5p6440() +#else +# define soc_is_s5p6440() 0 +#endif + +#if defined(CONFIG_CPU_S5P6450) +# define soc_is_s5p6450() is_samsung_s5p6450() +#else +# define soc_is_s5p6450() 0 +#endif + +#if defined(CONFIG_CPU_S5PC100) +# define soc_is_s5pc100() is_samsung_s5pc100() +#else +# define soc_is_s5pc100() 0 +#endif + +#if defined(CONFIG_CPU_S5PV210) +# define soc_is_s5pv210() is_samsung_s5pv210() +#else +# define soc_is_s5pv210() 0 +#endif + +#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE } + +#ifndef KHZ +#define KHZ (1000) +#endif + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000) + +/* forward declaration */ +struct s3c24xx_uart_resources; +struct platform_device; +struct s3c2410_uartcfg; +struct map_desc; + +/* per-cpu initialisation function table. */ + +struct cpu_table { + unsigned long idcode; + unsigned long idmask; + void (*map_io)(void); + void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no); + void (*init_clocks)(int xtal); + int (*init)(void); + const char *name; +}; + +extern void s3c_init_cpu(unsigned long idcode, + struct cpu_table *cpus, unsigned int cputab_size); + +/* core initialisation functions */ + +extern void s5p_init_irq(u32 *vic, u32 num_vic); + +extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); + +extern void s3c64xx_init_cpu(void); +extern void s5p_init_cpu(void __iomem *cpuid_addr); + +extern unsigned int samsung_rev(void); + +extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c24xx_init_clocks(int xtal); + +extern void s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no); + +extern struct syscore_ops s3c2410_pm_syscore_ops; +extern struct syscore_ops s3c2412_pm_syscore_ops; +extern struct syscore_ops s3c2416_pm_syscore_ops; +extern struct syscore_ops s3c244x_pm_syscore_ops; + +/* system device subsystems */ + +extern struct bus_type s3c2410_subsys; +extern struct bus_type s3c2410a_subsys; +extern struct bus_type s3c2412_subsys; +extern struct bus_type s3c2416_subsys; +extern struct bus_type s3c2440_subsys; +extern struct bus_type s3c2442_subsys; +extern struct bus_type s3c2443_subsys; +extern struct bus_type s3c6410_subsys; +extern struct bus_type s5p64x0_subsys; +extern struct bus_type s5pv210_subsys; + +extern void (*s5pc1xx_idle)(void); + +#endif diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h new file mode 100644 index 00000000000..eece188ed18 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -0,0 +1,159 @@ +/* arch/arm/plat-samsung/include/plat/devs.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for s3c2410 standard platform devices + * + * 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 __PLAT_DEVS_H +#define __PLAT_DEVS_H __FILE__ + +#include <linux/platform_device.h> + +struct s3c24xx_uart_resources { + struct resource *resources; + unsigned long nr_resources; +}; + +extern struct s3c24xx_uart_resources s3c2410_uart_resources[]; +extern struct s3c24xx_uart_resources s3c64xx_uart_resources[]; +extern struct s3c24xx_uart_resources s5p_uart_resources[]; +extern struct s3c24xx_uart_resources exynos4_uart_resources[]; +extern struct s3c24xx_uart_resources exynos5_uart_resources[]; + +extern struct platform_device *s3c24xx_uart_devs[]; +extern struct platform_device *s3c24xx_uart_src[]; + +extern struct platform_device s3c64xx_device_ac97; +extern struct platform_device s3c64xx_device_iis0; +extern struct platform_device s3c64xx_device_iis1; +extern struct platform_device s3c64xx_device_iisv4; +extern struct platform_device s3c64xx_device_onenand1; +extern struct platform_device s3c64xx_device_pcm0; +extern struct platform_device s3c64xx_device_pcm1; +extern struct platform_device s3c64xx_device_spi0; +extern struct platform_device s3c64xx_device_spi1; +extern struct platform_device s3c64xx_device_spi2; + +extern struct platform_device s3c_device_adc; +extern struct platform_device s3c_device_cfcon; +extern struct platform_device s3c_device_fb; +extern struct platform_device s3c_device_hwmon; +extern struct platform_device s3c_device_hsmmc0; +extern struct platform_device s3c_device_hsmmc1; +extern struct platform_device s3c_device_hsmmc2; +extern struct platform_device s3c_device_hsmmc3; +extern struct platform_device s3c_device_i2c0; +extern struct platform_device s3c_device_i2c1; +extern struct platform_device s3c_device_i2c2; +extern struct platform_device s3c_device_i2c3; +extern struct platform_device s3c_device_i2c4; +extern struct platform_device s3c_device_i2c5; +extern struct platform_device s3c_device_i2c6; +extern struct platform_device s3c_device_i2c7; +extern struct platform_device s3c_device_iis; +extern struct platform_device s3c_device_lcd; +extern struct platform_device s3c_device_nand; +extern struct platform_device s3c_device_ohci; +extern struct platform_device s3c_device_onenand; +extern struct platform_device s3c_device_rtc; +extern struct platform_device s3c_device_sdi; +extern struct platform_device s3c_device_spi0; +extern struct platform_device s3c_device_spi1; +extern struct platform_device s3c_device_ts; +extern struct platform_device s3c_device_timer[]; +extern struct platform_device s3c_device_usbgadget; +extern struct platform_device s3c_device_usb_hsotg; +extern struct platform_device s3c_device_usb_hsudc; +extern struct platform_device s3c_device_wdt; + +extern struct platform_device s5p_device_fimc0; +extern struct platform_device s5p_device_fimc1; +extern struct platform_device s5p_device_fimc2; +extern struct platform_device s5p_device_fimc3; +extern struct platform_device s5p_device_fimc_md; +extern struct platform_device s5p_device_jpeg; +extern struct platform_device s5p_device_g2d; +extern struct platform_device s5p_device_fimd0; +extern struct platform_device s5p_device_hdmi; +extern struct platform_device s5p_device_i2c_hdmiphy; +extern struct platform_device s5p_device_mfc; +extern struct platform_device s5p_device_mfc_l; +extern struct platform_device s5p_device_mfc_r; +extern struct platform_device s5p_device_mipi_csis0; +extern struct platform_device s5p_device_mipi_csis1; +extern struct platform_device s5p_device_mixer; +extern struct platform_device s5p_device_onenand; +extern struct platform_device s5p_device_sdo; + +extern struct platform_device s5p6440_device_iis; +extern struct platform_device s5p6440_device_pcm; + +extern struct platform_device s5p6450_device_iis0; +extern struct platform_device s5p6450_device_iis1; +extern struct platform_device s5p6450_device_iis2; +extern struct platform_device s5p6450_device_pcm0; + + +extern struct platform_device s5pc100_device_ac97; +extern struct platform_device s5pc100_device_iis0; +extern struct platform_device s5pc100_device_iis1; +extern struct platform_device s5pc100_device_iis2; +extern struct platform_device s5pc100_device_pcm0; +extern struct platform_device s5pc100_device_pcm1; +extern struct platform_device s5pc100_device_spdif; + +extern struct platform_device s5pv210_device_ac97; +extern struct platform_device s5pv210_device_iis0; +extern struct platform_device s5pv210_device_iis1; +extern struct platform_device s5pv210_device_iis2; +extern struct platform_device s5pv210_device_pcm0; +extern struct platform_device s5pv210_device_pcm1; +extern struct platform_device s5pv210_device_pcm2; +extern struct platform_device s5pv210_device_spdif; + +extern struct platform_device exynos4_device_ac97; +extern struct platform_device exynos4_device_ahci; +extern struct platform_device exynos4_device_i2s0; +extern struct platform_device exynos4_device_i2s1; +extern struct platform_device exynos4_device_i2s2; +extern struct platform_device exynos4_device_ohci; +extern struct platform_device exynos4_device_pcm0; +extern struct platform_device exynos4_device_pcm1; +extern struct platform_device exynos4_device_pcm2; +extern struct platform_device exynos4_device_spdif; + +extern struct platform_device samsung_asoc_idma; +extern struct platform_device samsung_device_keypad; +extern struct platform_device samsung_device_pwm; + +/* s3c2440 specific devices */ + +#ifdef CONFIG_CPU_S3C2440 + +extern struct platform_device s3c_device_camif; +extern struct platform_device s3c_device_ac97; + +#endif + +/** + * s3c_set_platdata() - helper for setting platform data + * @pd: The default platform data for this device. + * @pdsize: The size of the platform data. + * @pdev: Pointer to the device to fill in. + * + * This helper replaces a number of calls that copy and then set the + * platform data of the device. + */ +extern void *s3c_set_platdata(void *pd, size_t pdsize, + struct platform_device *pdev); + +#endif /* __PLAT_DEVS_H */ diff --git a/arch/arm/plat-samsung/include/plat/dma-core.h b/arch/arm/plat-samsung/include/plat/dma-core.h new file mode 100644 index 00000000000..32ff2a92cb3 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-core.h @@ -0,0 +1,22 @@ +/* arch/arm/plat-s3c/include/plat/dma.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Samsung S3C DMA core support + * + * 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. +*/ + +extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel); + +extern struct s3c2410_dma_chan *s3c_dma_chan_map[]; + +/* the currently allocated channel information */ +extern struct s3c2410_dma_chan s3c2410_chans[]; + + diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h new file mode 100644 index 00000000000..ce6d7634b6c --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -0,0 +1,69 @@ +/* arch/arm/plat-samsung/include/plat/dma-ops.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung DMA support + * + * 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 __SAMSUNG_DMA_OPS_H_ +#define __SAMSUNG_DMA_OPS_H_ __FILE__ + +#include <linux/dmaengine.h> +#include <mach/dma.h> + +struct samsung_dma_req { + enum dma_transaction_type cap; + struct s3c2410_dma_client *client; +}; + +struct samsung_dma_prep { + enum dma_transaction_type cap; + enum dma_transfer_direction direction; + dma_addr_t buf; + unsigned long period; + unsigned long len; + void (*fp)(void *data); + void *fp_param; +}; + +struct samsung_dma_config { + enum dma_transfer_direction direction; + enum dma_slave_buswidth width; + dma_addr_t fifo; +}; + +struct samsung_dma_ops { + unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param, + struct device *dev, char *ch_name); + int (*release)(unsigned ch, void *param); + int (*config)(unsigned ch, struct samsung_dma_config *param); + int (*prepare)(unsigned ch, struct samsung_dma_prep *param); + int (*trigger)(unsigned ch); + int (*started)(unsigned ch); + int (*flush)(unsigned ch); + int (*stop)(unsigned ch); +}; + +extern void *samsung_dmadev_get_ops(void); +extern void *s3c_dma_get_ops(void); + +static inline void *__samsung_dma_get_ops(void) +{ + if (samsung_dma_is_dmadev()) + return samsung_dmadev_get_ops(); + else + return s3c_dma_get_ops(); +} + +/* + * samsung_dma_get_ops + * get the set of samsung dma operations + */ +#define samsung_dma_get_ops() __samsung_dma_get_ops() + +#endif /* __SAMSUNG_DMA_OPS_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h new file mode 100644 index 00000000000..abe07fae71d --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2010 Samsung Electronics Co. Ltd. + * Jaswinder Singh <jassi.brar@samsung.com> + * + * 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 __DMA_PL330_H_ +#define __DMA_PL330_H_ __FILE__ + +/* + * PL330 can assign any channel to communicate with + * any of the peripherals attched to the DMAC. + * For the sake of consistency across client drivers, + * We keep the channel names unchanged and only add + * missing peripherals are added. + * Order is not important since DMA PL330 API driver + * use these just as IDs. + */ +enum dma_ch { + DMACH_UART0_RX = 0, + DMACH_UART0_TX, + DMACH_UART1_RX, + DMACH_UART1_TX, + DMACH_UART2_RX, + DMACH_UART2_TX, + DMACH_UART3_RX, + DMACH_UART3_TX, + DMACH_UART4_RX, + DMACH_UART4_TX, + DMACH_UART5_RX, + DMACH_UART5_TX, + DMACH_USI_RX, + DMACH_USI_TX, + DMACH_IRDA, + DMACH_I2S0_RX, + DMACH_I2S0_TX, + DMACH_I2S0S_TX, + DMACH_I2S1_RX, + DMACH_I2S1_TX, + DMACH_I2S2_RX, + DMACH_I2S2_TX, + DMACH_SPI0_RX, + DMACH_SPI0_TX, + DMACH_SPI1_RX, + DMACH_SPI1_TX, + DMACH_SPI2_RX, + DMACH_SPI2_TX, + DMACH_AC97_MICIN, + DMACH_AC97_PCMIN, + DMACH_AC97_PCMOUT, + DMACH_EXTERNAL, + DMACH_PWM, + DMACH_SPDIF, + DMACH_HSI_RX, + DMACH_HSI_TX, + DMACH_PCM0_TX, + DMACH_PCM0_RX, + DMACH_PCM1_TX, + DMACH_PCM1_RX, + DMACH_PCM2_TX, + DMACH_PCM2_RX, + DMACH_MSM_REQ3, + DMACH_MSM_REQ2, + DMACH_MSM_REQ1, + DMACH_MSM_REQ0, + DMACH_SLIMBUS0_RX, + DMACH_SLIMBUS0_TX, + DMACH_SLIMBUS0AUX_RX, + DMACH_SLIMBUS0AUX_TX, + DMACH_SLIMBUS1_RX, + DMACH_SLIMBUS1_TX, + DMACH_SLIMBUS2_RX, + DMACH_SLIMBUS2_TX, + DMACH_SLIMBUS3_RX, + DMACH_SLIMBUS3_TX, + DMACH_SLIMBUS4_RX, + DMACH_SLIMBUS4_TX, + DMACH_SLIMBUS5_RX, + DMACH_SLIMBUS5_TX, + DMACH_MIPI_HSI0, + DMACH_MIPI_HSI1, + DMACH_MIPI_HSI2, + DMACH_MIPI_HSI3, + DMACH_MIPI_HSI4, + DMACH_MIPI_HSI5, + DMACH_MIPI_HSI6, + DMACH_MIPI_HSI7, + DMACH_DISP1, + DMACH_MTOM_0, + DMACH_MTOM_1, + DMACH_MTOM_2, + DMACH_MTOM_3, + DMACH_MTOM_4, + DMACH_MTOM_5, + DMACH_MTOM_6, + DMACH_MTOM_7, + /* END Marker, also used to denote a reserved channel */ + DMACH_MAX, +}; + +struct s3c2410_dma_client { + char *name; +}; + +static inline bool samsung_dma_has_circular(void) +{ + return true; +} + +static inline bool samsung_dma_is_dmadev(void) +{ + return true; +} + +#include <plat/dma-ops.h> + +#endif /* __DMA_PL330_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h new file mode 100644 index 00000000000..bd3a6db14cb --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h @@ -0,0 +1,73 @@ +/* linux/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h + * + * Copyright (C) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C24XX DMA support - per SoC functions + * + * 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 <plat/dma-core.h> + +extern struct bus_type dma_subsys; +extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; + +#define DMA_CH_VALID (1<<31) +#define DMA_CH_NEVER (1<<30) + +/* struct s3c24xx_dma_map + * + * this holds the mapping information for the channel selected + * to be connected to the specified device +*/ + +struct s3c24xx_dma_map { + const char *name; + + unsigned long channels[S3C_DMA_CHANNELS]; +}; + +struct s3c24xx_dma_selection { + struct s3c24xx_dma_map *map; + unsigned long map_size; + unsigned long dcon_mask; + + void (*select)(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map); +}; + +extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); + +/* struct s3c24xx_dma_order_ch + * + * channel map for one of the `enum dma_ch` dma channels. the list + * entry contains a set of low-level channel numbers, orred with + * DMA_CH_VALID, which are checked in the order in the array. +*/ + +struct s3c24xx_dma_order_ch { + unsigned int list[S3C_DMA_CHANNELS]; /* list of channels */ + unsigned int flags; /* flags */ +}; + +/* struct s3c24xx_dma_order + * + * information provided by either the core or the board to give the + * dma system a hint on how to allocate channels +*/ + +struct s3c24xx_dma_order { + struct s3c24xx_dma_order_ch channels[DMACH_MAX]; +}; + +extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map); + +/* DMA init code, called from the cpu support code */ + +extern int s3c2410_dma_init(void); + +extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq, + unsigned int stride); diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h new file mode 100644 index 00000000000..7b02143ccd9 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -0,0 +1,130 @@ +/* arch/arm/plat-samsung/include/plat/dma.h + * + * Copyright (C) 2003-2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C DMA support + * + * 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 __PLAT_DMA_H +#define __PLAT_DMA_H + +#include <linux/dma-mapping.h> + +enum s3c2410_dma_buffresult { + S3C2410_RES_OK, + S3C2410_RES_ERR, + S3C2410_RES_ABORT +}; + +/* enum s3c2410_chan_op + * + * operation codes passed to the DMA code by the user, and also used + * to inform the current channel owner of any changes to the system state +*/ + +enum s3c2410_chan_op { + S3C2410_DMAOP_START, + S3C2410_DMAOP_STOP, + S3C2410_DMAOP_PAUSE, + S3C2410_DMAOP_RESUME, + S3C2410_DMAOP_FLUSH, + S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */ + S3C2410_DMAOP_STARTED, /* indicate channel started */ +}; + +struct s3c2410_dma_client { + char *name; +}; + +struct s3c2410_dma_chan; +enum dma_ch; + +/* s3c2410_dma_cbfn_t + * + * buffer callback routine type +*/ + +typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *, + void *buf, int size, + enum s3c2410_dma_buffresult result); + +typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, + enum s3c2410_chan_op ); + + + +/* s3c2410_dma_request + * + * request a dma channel exclusivley +*/ + +extern int s3c2410_dma_request(enum dma_ch channel, + struct s3c2410_dma_client *, void *dev); + + +/* s3c2410_dma_ctrl + * + * change the state of the dma channel +*/ + +extern int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op); + +/* s3c2410_dma_setflags + * + * set the channel's flags to a given state +*/ + +extern int s3c2410_dma_setflags(enum dma_ch channel, + unsigned int flags); + +/* s3c2410_dma_free + * + * free the dma channel (will also abort any outstanding operations) +*/ + +extern int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *); + +/* s3c2410_dma_enqueue + * + * place the given buffer onto the queue of operations for the channel. + * The buffer must be allocated from dma coherent memory, or the Dcache/WB + * drained before the buffer is given to the DMA system. +*/ + +extern int s3c2410_dma_enqueue(enum dma_ch channel, void *id, + dma_addr_t data, int size); + +/* s3c2410_dma_config + * + * configure the dma channel +*/ + +extern int s3c2410_dma_config(enum dma_ch channel, int xferunit); + +/* s3c2410_dma_devconfig + * + * configure the device we're talking to +*/ + +extern int s3c2410_dma_devconfig(enum dma_ch channel, + enum dma_data_direction source, unsigned long devaddr); + +/* s3c2410_dma_getposition + * + * get the position that the dma transfer is currently at +*/ + +extern int s3c2410_dma_getposition(enum dma_ch channel, + dma_addr_t *src, dma_addr_t *dest); + +extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); +extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); + +#include <plat/dma-ops.h> + +#endif diff --git a/arch/arm/plat-samsung/include/plat/fb-core.h b/arch/arm/plat-samsung/include/plat/fb-core.h new file mode 100644 index 00000000000..6abcbf139ce --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/fb-core.h @@ -0,0 +1,44 @@ +/* + * arch/arm/plat-samsung/include/plat/fb-core.h + * + * Copyright 2010 Samsung Electronics Co., Ltd. + * Pawel Osciak <p.osciak@samsung.com> + * + * Samsung framebuffer driver core functions + * + * 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 __ASM_PLAT_FB_CORE_H +#define __ASM_PLAT_FB_CORE_H __FILE__ + +/* + * These functions are only for use with the core support code, such as + * the CPU-specific initialization code. + */ + +/* Re-define device name depending on support. */ +static inline void s3c_fb_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_FB + s3c_device_fb.name = name; +#endif +} + +/* Re-define device name depending on support. */ +static inline void s5p_fb_setname(int id, char *name) +{ + switch (id) { +#ifdef CONFIG_S5P_DEV_FIMD0 + case 0: + s5p_device_fimd0.name = name; + break; +#endif + default: + printk(KERN_ERR "%s: invalid device id(%d)\n", __func__, id); + break; + } +} + +#endif /* __ASM_PLAT_FB_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/fb-s3c2410.h b/arch/arm/plat-samsung/include/plat/fb-s3c2410.h new file mode 100644 index 00000000000..4e5d9588b5b --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/fb-s3c2410.h @@ -0,0 +1,72 @@ +/* arch/arm/plat-samsung/include/plat/fb-s3c2410.h + * + * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org> + * + * Inspired by pxafb.h + * + * 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 __ASM_PLAT_FB_S3C2410_H +#define __ASM_PLAT_FB_S3C2410_H __FILE__ + +struct s3c2410fb_hw { + unsigned long lcdcon1; + unsigned long lcdcon2; + unsigned long lcdcon3; + unsigned long lcdcon4; + unsigned long lcdcon5; +}; + +/* LCD description */ +struct s3c2410fb_display { + /* LCD type */ + unsigned type; + + /* Screen size */ + unsigned short width; + unsigned short height; + + /* Screen info */ + unsigned short xres; + unsigned short yres; + unsigned short bpp; + + unsigned pixclock; /* pixclock in picoseconds */ + unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */ + unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */ + unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */ + unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */ + unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */ + unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */ + + /* lcd configuration registers */ + unsigned long lcdcon5; +}; + +struct s3c2410fb_mach_info { + + struct s3c2410fb_display *displays; /* attached diplays info */ + unsigned num_displays; /* number of defined displays */ + unsigned default_display; + + /* GPIOs */ + + unsigned long gpcup; + unsigned long gpcup_mask; + unsigned long gpccon; + unsigned long gpccon_mask; + unsigned long gpdup; + unsigned long gpdup_mask; + unsigned long gpdcon; + unsigned long gpdcon_mask; + + /* lpc3600 control register */ + unsigned long lpcsel; +}; + +extern void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *); + +#endif /* __ASM_PLAT_FB_S3C2410_H */ diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h new file mode 100644 index 00000000000..9ae50727078 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/fb.h @@ -0,0 +1,71 @@ +/* arch/arm/plat-samsung/include/plat/fb.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - FB platform data definitions + * + * 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 __PLAT_S3C_FB_H +#define __PLAT_S3C_FB_H __FILE__ + +#include <linux/platform_data/video_s3c.h> + +/** + * s3c_fb_set_platdata() - Setup the FB device with platform data. + * @pd: The platform data to set. The data is copied from the passed structure + * so the machine data can mark the data __initdata so that any unused + * machines will end up dumping their data at runtime. + */ +extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd); + +/** + * s5p_fimd0_set_platdata() - Setup the FB device with platform data. + * @pd: The platform data to set. The data is copied from the passed structure + * so the machine data can mark the data __initdata so that any unused + * machines will end up dumping their data at runtime. + */ +extern void s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd); + +/** + * s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s3c64xx_fb_gpio_setup_24bpp(void); + +/** + * s5pc100_fb_gpio_setup_24bpp() - S5PC100 setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s5pc100_fb_gpio_setup_24bpp(void); + +/** + * s5pv210_fb_gpio_setup_24bpp() - S5PV210/S5PC110 setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s5pv210_fb_gpio_setup_24bpp(void); + +/** + * exynos4_fimd0_gpio_setup_24bpp() - Exynos4 setup function for 24bpp LCD0 + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface 0. + */ +extern void exynos4_fimd0_gpio_setup_24bpp(void); + +/** + * s5p64x0_fb_gpio_setup_24bpp() - S5P6440/S5P6450 setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s5p64x0_fb_gpio_setup_24bpp(void); + +#endif /* __PLAT_S3C_FB_H */ diff --git a/arch/arm/plat-samsung/include/plat/fimc-core.h b/arch/arm/plat-samsung/include/plat/fimc-core.h new file mode 100644 index 00000000000..1d6cb2b8b09 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/fimc-core.h @@ -0,0 +1,51 @@ +/* + * arch/arm/plat-samsung/include/plat/fimc-core.h + * + * Copyright 2010 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki <s.nawrocki@samsung.com> + * + * Samsung camera interface driver core functions + * + * 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 __ASM_PLAT_FIMC_CORE_H +#define __ASM_PLAT_FIMC_CORE_H __FILE__ + +/* + * These functions are only for use with the core support code, such as + * the CPU-specific initialization code. + */ + +/* Re-define device name to differentiate the subsystem in various SoCs. */ +static inline void s3c_fimc_setname(int id, char *name) +{ + switch (id) { +#ifdef CONFIG_S5P_DEV_FIMC0 + case 0: + s5p_device_fimc0.name = name; + break; +#endif +#ifdef CONFIG_S5P_DEV_FIMC1 + case 1: + s5p_device_fimc1.name = name; + break; +#endif +#ifdef CONFIG_S5P_DEV_FIMC2 + case 2: + s5p_device_fimc2.name = name; + break; +#endif +#ifdef CONFIG_S5P_DEV_FIMC3 + case 3: + s5p_device_fimc3.name = name; + break; +#endif + default: + break; + } +} + +#endif /* __ASM_PLAT_FIMC_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h new file mode 100644 index 00000000000..a181d7ce81c --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h @@ -0,0 +1,163 @@ +/* linux/arch/arm/plat-samsung/include/plat/gpio-cfg-helper.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung Platform - GPIO pin configuration helper definitions + * + * 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. +*/ + +/* This is meant for core cpu support, machine or other driver files + * should not be including this header. + */ + +#ifndef __PLAT_GPIO_CFG_HELPERS_H +#define __PLAT_GPIO_CFG_HELPERS_H __FILE__ + +/* As a note, all gpio configuration functions are entered exclusively, either + * with the relevant lock held or the system prevented from doing anything else + * by disabling interrupts. +*/ + +static inline int samsung_gpio_do_setcfg(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int config) +{ + return (chip->config->set_config)(chip, off, config); +} + +static inline unsigned samsung_gpio_do_getcfg(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return (chip->config->get_config)(chip, off); +} + +static inline int samsung_gpio_do_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return (chip->config->set_pull)(chip, off, pull); +} + +static inline samsung_gpio_pull_t samsung_gpio_do_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return chip->config->get_pull(chip, off); +} + +/* Pull-{up,down} resistor controls. + * + * S3C2410,S3C2440 = Pull-UP, + * S3C2412,S3C2413 = Pull-Down + * S3C6400,S3C6410 = Pull-Both [None,Down,Up,Undef] + * S3C2443 = Pull-Both [not same as S3C6400] + */ + +/** + * s3c24xx_gpio_setpull_1up() - Pull configuration for choice of up or none. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with one + * bit configuring the presence of a pull-up resistor. + */ +extern int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * s3c24xx_gpio_setpull_1down() - Pull configuration for choice of down or none + * @chip: The gpio chip that is being configured + * @off: The offset for the GPIO being configured + * @param: pull: The pull mode being requested + * + * This is a helper function for the case where we have GPIOs with one + * bit configuring the presence of a pull-down resistor. + */ +extern int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * samsung_gpio_setpull_upown() - Pull configuration for choice of up, + * down or none + * + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with two + * bits configuring the presence of a pull resistor, in the following + * order: + * 00 = No pull resistor connected + * 01 = Pull-up resistor connected + * 10 = Pull-down resistor connected + */ +extern int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * samsung_gpio_getpull_updown() - Get configuration for choice of up, + * down or none + * + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-{up,down} resistor + * for the given GPIO in the same case as samsung_gpio_setpull_upown. +*/ +extern samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c24xx_gpio_getpull_1up() - Get configuration for choice of up or none + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-up resistor for the + * given GPIO in the same case as s3c24xx_gpio_setpull_1up. +*/ +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c24xx_gpio_getpull_1down() - Get configuration for choice of down or none + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-down resistor for the + * given GPIO in the same case as s3c24xx_gpio_setpull_1down. +*/ +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c2443_gpio_setpull() - Pull configuration for s3c2443. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with two + * bits configuring the presence of a pull resistor, in the following + * order: + * 00 = Pull-up resistor connected + * 10 = Pull-down resistor connected + * x1 = No pull up resistor + */ +extern int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * s3c2443_gpio_getpull() - Get configuration for s3c2443 pull resistors + * @chip: The gpio chip that the GPIO pin belongs to. + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-{up,down} resistor for the + * given GPIO in the same case as samsung_gpio_setpull_upown. +*/ +extern samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off); + +#endif /* __PLAT_GPIO_CFG_HELPERS_H */ diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h new file mode 100644 index 00000000000..08740eed050 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h @@ -0,0 +1,246 @@ +/* linux/arch/arm/plat-s3c/include/plat/gpio-cfg.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - GPIO pin configuration + * + * 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. +*/ + +/* This file contains the necessary definitions to get the basic gpio + * pin configuration done such as setting a pin to input or output or + * changing the pull-{up,down} configurations. + */ + +/* Note, this interface is being added to the s3c64xx arch first and will + * be added to the s3c24xx systems later. + */ + +#ifndef __PLAT_GPIO_CFG_H +#define __PLAT_GPIO_CFG_H __FILE__ + +#include <linux/types.h> + +typedef unsigned int __bitwise__ samsung_gpio_pull_t; +typedef unsigned int __bitwise__ s5p_gpio_drvstr_t; + +/* forward declaration if gpio-core.h hasn't been included */ +struct samsung_gpio_chip; + +/** + * struct samsung_gpio_cfg GPIO configuration + * @cfg_eint: Configuration setting when used for external interrupt source + * @get_pull: Read the current pull configuration for the GPIO + * @set_pull: Set the current pull configuraiton for the GPIO + * @set_config: Set the current configuration for the GPIO + * @get_config: Read the current configuration for the GPIO + * + * Each chip can have more than one type of GPIO bank available and some + * have different capabilites even when they have the same control register + * layouts. Provide an point to vector control routine and provide any + * per-bank configuration information that other systems such as the + * external interrupt code will need. + * + * @sa samsung_gpio_cfgpin + * @sa s3c_gpio_getcfg + * @sa s3c_gpio_setpull + * @sa s3c_gpio_getpull + */ +struct samsung_gpio_cfg { + unsigned int cfg_eint; + + samsung_gpio_pull_t (*get_pull)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_pull)(struct samsung_gpio_chip *chip, unsigned offs, + samsung_gpio_pull_t pull); + + unsigned (*get_config)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_config)(struct samsung_gpio_chip *chip, unsigned offs, + unsigned config); +}; + +#define S3C_GPIO_SPECIAL_MARK (0xfffffff0) +#define S3C_GPIO_SPECIAL(x) (S3C_GPIO_SPECIAL_MARK | (x)) + +/* Defines for generic pin configurations */ +#define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0)) +#define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) +#define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x)) + +#define samsung_gpio_is_cfg_special(_cfg) \ + (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK) + +/** + * s3c_gpio_cfgpin() - Change the GPIO function of a pin. + * @pin pin The pin number to configure. + * @to to The configuration for the pin's function. + * + * Configure which function is actually connected to the external + * pin, such as an gpio input, output or some form of special function + * connected to an internal peripheral block. + * + * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT + * or S3C_GPIO_SFN() to indicate one of the possible values that the helper + * will then generate the correct bit mask and shift for the configuration. + * + * If a bank of GPIOs all needs to be set to special-function 2, then + * the following code will work: + * + * for (gpio = start; gpio < end; gpio++) + * s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + * + * The @to parameter can also be a specific value already shifted to the + * correct position in the control register, although these are discouraged + * in newer kernels and are only being kept for compatibility. + */ +extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to); + +/** + * s3c_gpio_getcfg - Read the current function for a GPIO pin + * @pin: The pin to read the configuration value for. + * + * Read the configuration state of the given @pin, returning a value that + * could be passed back to s3c_gpio_cfgpin(). + * + * @sa s3c_gpio_cfgpin + */ +extern unsigned s3c_gpio_getcfg(unsigned int pin); + +/** + * s3c_gpio_cfgpin_range() - Change the GPIO function for configuring pin range + * @start: The pin number to start at + * @nr: The number of pins to configure from @start. + * @cfg: The configuration for the pin's function + * + * Call s3c_gpio_cfgpin() for the @nr pins starting at @start. + * + * @sa s3c_gpio_cfgpin. + */ +extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, + unsigned int cfg); + +/* Define values for the pull-{up,down} available for each gpio pin. + * + * These values control the state of the weak pull-{up,down} resistors + * available on most pins on the S3C series. Not all chips support both + * up or down settings, and it may be dependent on the chip that is being + * used to whether the particular mode is available. + */ +#define S3C_GPIO_PULL_NONE ((__force samsung_gpio_pull_t)0x00) +#define S3C_GPIO_PULL_DOWN ((__force samsung_gpio_pull_t)0x01) +#define S3C_GPIO_PULL_UP ((__force samsung_gpio_pull_t)0x02) + +/** + * s3c_gpio_setpull() - set the state of a gpio pin pull resistor + * @pin: The pin number to configure the pull resistor. + * @pull: The configuration for the pull resistor. + * + * This function sets the state of the pull-{up,down} resistor for the + * specified pin. It will return 0 if successful, or a negative error + * code if the pin cannot support the requested pull setting. + * + * @pull is one of S3C_GPIO_PULL_NONE, S3C_GPIO_PULL_DOWN or S3C_GPIO_PULL_UP. +*/ +extern int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull); + +/** + * s3c_gpio_getpull() - get the pull resistor state of a gpio pin + * @pin: The pin number to get the settings for + * + * Read the pull resistor value for the specified pin. +*/ +extern samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin); + +/* configure `all` aspects of an gpio */ + +/** + * s3c_gpio_cfgall_range() - configure range of gpio functtion and pull. + * @start: The gpio number to start at. + * @nr: The number of gpio to configure from @start. + * @cfg: The configuration to use + * @pull: The pull setting to use. + * + * Run s3c_gpio_cfgpin() and s3c_gpio_setpull() over the gpio range starting + * @gpio and running for @size. + * + * @sa s3c_gpio_cfgpin + * @sa s3c_gpio_setpull + * @sa s3c_gpio_cfgpin_range + */ +extern int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, + unsigned int cfg, samsung_gpio_pull_t pull); + +static inline int s3c_gpio_cfgrange_nopull(unsigned int pin, unsigned int size, + unsigned int cfg) +{ + return s3c_gpio_cfgall_range(pin, size, cfg, S3C_GPIO_PULL_NONE); +} + +/* Define values for the drvstr available for each gpio pin. + * + * These values control the value of the output signal driver strength, + * configurable on most pins on the S5P series. + */ +#define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x0) +#define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x2) +#define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x1) +#define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x3) + +/** + * s5c_gpio_get_drvstr() - get the driver streght value of a gpio pin + * @pin: The pin number to get the settings for + * + * Read the driver streght value for the specified pin. +*/ +extern s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin); + +/** + * s3c_gpio_set_drvstr() - set the driver streght value of a gpio pin + * @pin: The pin number to configure the driver streght value + * @drvstr: The new value of the driver strength + * + * This function sets the driver strength value for the specified pin. + * It will return 0 if successful, or a negative error code if the pin + * cannot support the requested setting. +*/ +extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr); + +/** + * s5p_register_gpio_interrupt() - register interrupt support for a gpio group + * @pin: The pin number from the group to be registered + * + * This function registers gpio interrupt support for the group that the + * specified pin belongs to. + * + * The total number of gpio pins is quite large ob s5p series. Registering + * irq support for all of them would be a resource waste. Because of that the + * interrupt support for standard gpio pins is registered dynamically. + * + * It will return the irq number of the interrupt that has been registered + * or -ENOMEM if no more gpio interrupts can be registered. It is allowed + * to call this function more than once for the same gpio group (the group + * will be registered only once). + */ +extern int s5p_register_gpio_interrupt(int pin); + +/** s5p_register_gpioint_bank() - add gpio bank for further gpio interrupt + * registration (see s5p_register_gpio_interrupt function) + * @chain_irq: chained irq number for the gpio int handler for this bank + * @start: start gpio group number of this bank + * @nr_groups: number of gpio groups handled by this bank + * + * This functions registers initial information about gpio banks that + * can be later used by the s5p_register_gpio_interrupt() function to + * enable support for gpio interrupt for particular gpio group. + */ +#ifdef CONFIG_S5P_GPIO_INT +extern int s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups); +#else +#define s5p_register_gpioint_bank(chain_irq, start, nr_groups) do { } while (0) +#endif + +#endif /* __PLAT_GPIO_CFG_H */ diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h new file mode 100644 index 00000000000..cf5aae5b097 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h @@ -0,0 +1,142 @@ +/* linux/arch/arm/plat-s3c/include/plat/gpio-core.h + * + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - GPIO core + * + * 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 __PLAT_SAMSUNG_GPIO_CORE_H +#define __PLAT_SAMSUNG_GPIO_CORE_H + +#define GPIOCON_OFF (0x00) +#define GPIODAT_OFF (0x04) + +#define con_4bit_shift(__off) ((__off) * 4) + +/* Define the core gpiolib support functions that the s3c platforms may + * need to extend or change depending on the hardware and the s3c chip + * selected at build or found at run time. + * + * These definitions are not intended for driver inclusion, there is + * nothing here that should not live outside the platform and core + * specific code. +*/ + +struct samsung_gpio_chip; + +/** + * struct samsung_gpio_pm - power management (suspend/resume) information + * @save: Routine to save the state of the GPIO block + * @resume: Routine to resume the GPIO block. + */ +struct samsung_gpio_pm { + void (*save)(struct samsung_gpio_chip *chip); + void (*resume)(struct samsung_gpio_chip *chip); +}; + +struct samsung_gpio_cfg; + +/** + * struct samsung_gpio_chip - wrapper for specific implementation of gpio + * @chip: The chip structure to be exported via gpiolib. + * @base: The base pointer to the gpio configuration registers. + * @group: The group register number for gpio interrupt support. + * @irq_base: The base irq number. + * @config: special function and pull-resistor control information. + * @lock: Lock for exclusive access to this gpio bank. + * @pm_save: Save information for suspend/resume support. + * @bitmap_gpio_int: Bitmap for representing GPIO interrupt or not. + * + * This wrapper provides the necessary information for the Samsung + * specific gpios being registered with gpiolib. + * + * The lock protects each gpio bank from multiple access of the shared + * configuration registers, or from reading of data whilst another thread + * is writing to the register set. + * + * Each chip has its own lock to avoid any contention between different + * CPU cores trying to get one lock for different GPIO banks, where each + * bank of GPIO has its own register space and configuration registers. + */ +struct samsung_gpio_chip { + struct gpio_chip chip; + struct samsung_gpio_cfg *config; + struct samsung_gpio_pm *pm; + void __iomem *base; + int irq_base; + int group; + spinlock_t lock; +#ifdef CONFIG_PM + u32 pm_save[4]; +#endif + u32 bitmap_gpio_int; +}; + +static inline struct samsung_gpio_chip *to_samsung_gpio(struct gpio_chip *gpc) +{ + return container_of(gpc, struct samsung_gpio_chip, chip); +} + +/** + * samsung_gpiolib_to_irq - convert gpio pin to irq number + * @chip: The gpio chip that the pin belongs to. + * @offset: The offset of the pin in the chip. + * + * This helper returns the irq number calculated from the chip->irq_base and + * the provided offset. + */ +extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset); + +/* exported for core SoC support to change */ +extern struct samsung_gpio_cfg s3c24xx_gpiocfg_default; + +#ifdef CONFIG_S3C_GPIO_TRACK +extern struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; + +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int chip) +{ + return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL; +} +#else +/* machine specific code should provide samsung_gpiolib_getchip */ + +extern struct samsung_gpio_chip s3c24xx_gpios[]; + +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin) +{ + struct samsung_gpio_chip *chip; + + if (pin > S3C_GPIO_END) + return NULL; + + chip = &s3c24xx_gpios[pin/32]; + return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL; +} + +static inline void s3c_gpiolib_track(struct samsung_gpio_chip *chip) { } +#endif + +#ifdef CONFIG_PM +extern struct samsung_gpio_pm samsung_gpio_pm_1bit; +extern struct samsung_gpio_pm samsung_gpio_pm_2bit; +extern struct samsung_gpio_pm samsung_gpio_pm_4bit; +#define __gpio_pm(x) x +#else +#define samsung_gpio_pm_1bit NULL +#define samsung_gpio_pm_2bit NULL +#define samsung_gpio_pm_4bit NULL +#define __gpio_pm(x) NULL + +#endif /* CONFIG_PM */ + +/* locking wrappers to deal with multiple access to the same gpio bank */ +#define samsung_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl) +#define samsung_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl) + +#endif /* __PLAT_SAMSUNG_GPIO_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/hdmi.h b/arch/arm/plat-samsung/include/plat/hdmi.h new file mode 100644 index 00000000000..331d046ac2c --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/hdmi.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.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. + */ + +#ifndef __PLAT_SAMSUNG_HDMI_H +#define __PLAT_SAMSUNG_HDMI_H __FILE__ + +extern void s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info, + struct i2c_board_info *mhl_info, int mhl_bus); + +#endif /* __PLAT_SAMSUNG_HDMI_H */ diff --git a/arch/arm/plat-samsung/include/plat/iic-core.h b/arch/arm/plat-samsung/include/plat/iic-core.h new file mode 100644 index 00000000000..f182669b8e8 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/iic-core.h @@ -0,0 +1,42 @@ +/* arch/arm/mach-s3c2410/include/mach/iic-core.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - I2C Controller core functions + * + * 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 __ASM_ARCH_IIC_CORE_H +#define __ASM_ARCH_IIC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_i2c0_setname(char *name) +{ + /* currently this device is always compiled in */ + s3c_device_i2c0.name = name; +} + +static inline void s3c_i2c1_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_I2C1 + s3c_device_i2c1.name = name; +#endif +} + +static inline void s3c_i2c2_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_I2C2 + s3c_device_i2c2.name = name; +#endif +} + +#endif /* __ASM_ARCH_IIC_H */ diff --git a/arch/arm/plat-samsung/include/plat/irq-uart.h b/arch/arm/plat-samsung/include/plat/irq-uart.h new file mode 100644 index 00000000000..a9331e49bea --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/irq-uart.h @@ -0,0 +1,20 @@ +/* arch/arm/plat-samsung/include/plat/irq-uart.h + * + * Copyright (c) 2010 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for Samsung SoC UART IRQ demux for S3C64XX and later + * + * 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. +*/ + +struct s3c_uart_irq { + void __iomem *regs; + unsigned int base_irq; + unsigned int parent_irq; +}; + +extern void s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs); + diff --git a/arch/arm/plat-samsung/include/plat/irqs.h b/arch/arm/plat-samsung/include/plat/irqs.h new file mode 100644 index 00000000000..039001c0ef0 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/irqs.h @@ -0,0 +1,72 @@ +/* linux/arch/arm/plat-samsung/include/plat/irqs.h + * + * Copyright (c) 2009 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P Common IRQ support + * + * 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 __PLAT_SAMSUNG_IRQS_H +#define __PLAT_SAMSUNG_IRQS_H __FILE__ + +/* we keep the first set of CPU IRQs out of the range of + * the ISA space, so that the PC104 has them to itself + * and we don't end up having to do horrible things to the + * standard ISA drivers.... + * + * note, since we're using the VICs, our start must be a + * mulitple of 32 to allow the common code to work + */ + +#define S5P_IRQ_OFFSET (32) + +#define S5P_IRQ(x) ((x) + S5P_IRQ_OFFSET) + +#define S5P_VIC0_BASE S5P_IRQ(0) +#define S5P_VIC1_BASE S5P_IRQ(32) +#define S5P_VIC2_BASE S5P_IRQ(64) +#define S5P_VIC3_BASE S5P_IRQ(96) + +#define VIC_BASE(x) (S5P_VIC0_BASE + ((x)*32)) + +#define IRQ_VIC0_BASE S5P_VIC0_BASE +#define IRQ_VIC1_BASE S5P_VIC1_BASE +#define IRQ_VIC2_BASE S5P_VIC2_BASE + +/* VIC based IRQs */ + +#define S5P_IRQ_VIC0(x) (S5P_VIC0_BASE + (x)) +#define S5P_IRQ_VIC1(x) (S5P_VIC1_BASE + (x)) +#define S5P_IRQ_VIC2(x) (S5P_VIC2_BASE + (x)) +#define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x)) + +#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \ + : ((x) - 16 + S5P_EINT_BASE2)) + +#define EINT_OFFSET(irq) ((irq) < S5P_EINT_BASE2 ? \ + ((irq) - S5P_EINT_BASE1) : \ + ((irq) + 16 - S5P_EINT_BASE2)) + +#define IRQ_EINT_BIT(x) EINT_OFFSET(x) + +/* Typically only a few gpio chips require gpio interrupt support. + To avoid memory waste irq descriptors are allocated only for + S5P_GPIOINT_GROUP_COUNT chips, each with total number of + S5P_GPIOINT_GROUP_SIZE pins/irqs. Each GPIOINT group can be assiged + to any gpio chip with the s5p_register_gpio_interrupt() function */ +#define S5P_GPIOINT_GROUP_COUNT 4 +#define S5P_GPIOINT_GROUP_SIZE 8 +#define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE) + +/* IRQ types common for all s5p platforms */ +#define S5P_IRQ_TYPE_LEVEL_LOW (0x00) +#define S5P_IRQ_TYPE_LEVEL_HIGH (0x01) +#define S5P_IRQ_TYPE_EDGE_FALLING (0x02) +#define S5P_IRQ_TYPE_EDGE_RISING (0x03) +#define S5P_IRQ_TYPE_EDGE_BOTH (0x04) + +#endif /* __PLAT_SAMSUNG_IRQS_H */ diff --git a/arch/arm/plat-samsung/include/plat/keypad-core.h b/arch/arm/plat-samsung/include/plat/keypad-core.h new file mode 100644 index 00000000000..d513e1b3a31 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/keypad-core.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/plat-samsung/include/plat/keypad-core.h + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * Samsung keypad controller core function + * + * 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 __ASM_ARCH_KEYPAD_CORE_H +#define __ASM_ARCH_KEYPAD_CORE_H + +/* These function are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void samsung_keypad_setname(char *name) +{ +#ifdef CONFIG_SAMSUNG_DEV_KEYPAD + samsung_device_keypad.name = name; +#endif +} + +#endif /* __ASM_ARCH_KEYPAD_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/keypad.h b/arch/arm/plat-samsung/include/plat/keypad.h new file mode 100644 index 00000000000..c81ace332a1 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/keypad.h @@ -0,0 +1,31 @@ +/* + * Samsung Platform - Keypad platform data definitions + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * 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 __PLAT_SAMSUNG_KEYPAD_H +#define __PLAT_SAMSUNG_KEYPAD_H + +#include <linux/input/samsung-keypad.h> + +/** + * samsung_keypad_set_platdata - Set platform data for Samsung Keypad device. + * @pd: Platform data to register to device. + * + * Register the given platform data for use with Samsung Keypad device. + * The call will copy the platform data, so the board definitions can + * make the structure itself __initdata. + */ +extern void samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd); + +/* defined by architecture to configure gpio. */ +extern void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols); + +#endif /* __PLAT_SAMSUNG_KEYPAD_H */ diff --git a/arch/arm/plat-samsung/include/plat/map-base.h b/arch/arm/plat-samsung/include/plat/map-base.h new file mode 100644 index 00000000000..3ffac4d2e4f --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/map-base.h @@ -0,0 +1,46 @@ +/* linux/include/asm-arm/plat-s3c/map.h + * + * Copyright 2003, 2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - Memory map definitions (virtual addresses) + * + * 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 __ASM_PLAT_MAP_H +#define __ASM_PLAT_MAP_H __FILE__ + +/* Fit all our registers in at 0xF6000000 upwards, trying to use as + * little of the VA space as possible so vmalloc and friends have a + * better chance of getting memory. + * + * we try to ensure stuff like the IRQ registers are available for + * an single MOVS instruction (ie, only 8 bits of set data) + */ + +#define S3C_ADDR_BASE 0xF6000000 + +#ifndef __ASSEMBLY__ +#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) +#else +#define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) +#endif + +#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */ +#define S3C_VA_SYS S3C_ADDR(0x00100000) /* system control */ +#define S3C_VA_MEM S3C_ADDR(0x00200000) /* memory control */ +#define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */ +#define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */ +#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ + +/* This is used for the CPU specific mappings that may be needed, so that + * they do not need to directly used S3C_ADDR() and thus make it easier to + * modify the space for mapping. + */ +#define S3C_ADDR_CPU(x) S3C_ADDR(0x00500000 + (x)) + +#endif /* __ASM_PLAT_MAP_H */ diff --git a/arch/arm/plat-samsung/include/plat/map-s3c.h b/arch/arm/plat-samsung/include/plat/map-s3c.h new file mode 100644 index 00000000000..c0c70a895ca --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/map-s3c.h @@ -0,0 +1,84 @@ +/* linux/arch/arm/plat-samsung/include/plat/map-s3c.h + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX - Memory map definitions + * + * 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 __ASM_PLAT_MAP_S3C_H +#define __ASM_PLAT_MAP_S3C_H __FILE__ + +#define S3C24XX_VA_IRQ S3C_VA_IRQ +#define S3C24XX_VA_MEMCTRL S3C_VA_MEM +#define S3C24XX_VA_UART S3C_VA_UART + +#define S3C24XX_VA_TIMER S3C_VA_TIMER +#define S3C24XX_VA_CLKPWR S3C_VA_SYS +#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG + +#define S3C2412_VA_SSMC S3C_ADDR_CPU(0x00000000) +#define S3C2412_VA_EBI S3C_ADDR_CPU(0x00100000) + +#define S3C2410_PA_UART (0x50000000) +#define S3C24XX_PA_UART S3C2410_PA_UART + +#ifndef S3C_UART_OFFSET +#define S3C_UART_OFFSET (0x400) +#endif + +/* + * GPIO ports + * + * the calculation for the VA of this must ensure that + * it is the same distance apart from the UART in the + * phsyical address space, as the initial mapping for the IO + * is done as a 1:1 mapping. This puts it (currently) at + * 0xFA800000, which is not in the way of any current mapping + * by the base system. +*/ + +#define S3C2410_PA_GPIO (0x56000000) +#define S3C24XX_PA_GPIO S3C2410_PA_GPIO + +#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART) +#define S3C64XX_VA_GPIO S3C_ADDR_CPU(0x00000000) + +#define S3C64XX_VA_MODEM S3C_ADDR_CPU(0x00100000) +#define S3C64XX_VA_USB_HSPHY S3C_ADDR_CPU(0x00200000) + +#define S3C_VA_USB_HSPHY S3C64XX_VA_USB_HSPHY + +/* + * ISA style IO, for each machine to sort out mappings for, + * if it implements it. We reserve two 16M regions for ISA. + */ + +#define S3C2410_ADDR(x) S3C_ADDR(x) + +#define S3C24XX_VA_ISA_WORD S3C2410_ADDR(0x02000000) +#define S3C24XX_VA_ISA_BYTE S3C2410_ADDR(0x03000000) + +/* deal with the registers that move under the 2412/2413 */ + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#ifndef __ASSEMBLY__ +extern void __iomem *s3c24xx_va_gpio2; +#endif +#ifdef CONFIG_CPU_S3C2412_ONLY +#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10) +#else +#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2 +#endif +#else +#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO +#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO +#endif + +#include <plat/map-s5p.h> + +#endif /* __ASM_PLAT_MAP_S3C_H */ diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h new file mode 100644 index 00000000000..c18678610bc --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/map-s5p.h @@ -0,0 +1,62 @@ +/* linux/arch/arm/plat-samsung/include/plat/map-s5p.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P - Memory map definitions + * + * 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 __ASM_PLAT_MAP_S5P_H +#define __ASM_PLAT_MAP_S5P_H __FILE__ + +#define S5P_VA_CHIPID S3C_ADDR(0x02000000) +#define S5P_VA_CMU S3C_ADDR(0x02100000) +#define S5P_VA_PMU S3C_ADDR(0x02180000) +#define S5P_VA_GPIO S3C_ADDR(0x02200000) +#define S5P_VA_GPIO1 S5P_VA_GPIO +#define S5P_VA_GPIO2 S3C_ADDR(0x02240000) +#define S5P_VA_GPIO3 S3C_ADDR(0x02280000) + +#define S5P_VA_SYSRAM S3C_ADDR(0x02400000) +#define S5P_VA_SYSRAM_NS S3C_ADDR(0x02410000) +#define S5P_VA_DMC0 S3C_ADDR(0x02440000) +#define S5P_VA_DMC1 S3C_ADDR(0x02480000) +#define S5P_VA_SROMC S3C_ADDR(0x024C0000) + +#define S5P_VA_SYSTIMER S3C_ADDR(0x02500000) +#define S5P_VA_L2CC S3C_ADDR(0x02600000) + +#define S5P_VA_COMBINER_BASE S3C_ADDR(0x02700000) +#define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) + +#define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000) +#define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) +#define S5P_VA_SCU S5P_VA_COREPERI(0x0) +#define S5P_VA_TWD S5P_VA_COREPERI(0x600) + +#define S5P_VA_GIC_CPU S3C_ADDR(0x02810000) +#define S5P_VA_GIC_DIST S3C_ADDR(0x02820000) + +#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) +#define VA_VIC0 VA_VIC(0) +#define VA_VIC1 VA_VIC(1) +#define VA_VIC2 VA_VIC(2) +#define VA_VIC3 VA_VIC(3) + +#define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) +#define S5P_VA_UART0 S5P_VA_UART(0) +#define S5P_VA_UART1 S5P_VA_UART(1) +#define S5P_VA_UART2 S5P_VA_UART(2) +#define S5P_VA_UART3 S5P_VA_UART(3) + +#ifndef S3C_UART_OFFSET +#define S3C_UART_OFFSET (0x400) +#endif + +#include <plat/map-s3c.h> + +#endif /* __ASM_PLAT_MAP_S5P_H */ diff --git a/arch/arm/plat-samsung/include/plat/mfc.h b/arch/arm/plat-samsung/include/plat/mfc.h new file mode 100644 index 00000000000..033654e91e2 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/mfc.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co.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. + */ + +#ifndef __PLAT_SAMSUNG_MFC_H +#define __PLAT_SAMSUNG_MFC_H __FILE__ + +struct s5p_mfc_dt_meminfo { + unsigned long loff; + unsigned long lsize; + unsigned long roff; + unsigned long rsize; + char *compatible; +}; + +/** + * s5p_mfc_reserve_mem - function to early reserve memory for MFC driver + * @rbase: base address for MFC 'right' memory interface + * @rsize: size of the memory reserved for MFC 'right' interface + * @lbase: base address for MFC 'left' memory interface + * @lsize: size of the memory reserved for MFC 'left' interface + * + * This function reserves system memory for both MFC device memory + * interfaces and registers it to respective struct device entries as + * coherent memory. + */ +void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize, + phys_addr_t lbase, unsigned int lsize); + +#endif /* __PLAT_SAMSUNG_MFC_H */ diff --git a/arch/arm/plat-samsung/include/plat/nand-core.h b/arch/arm/plat-samsung/include/plat/nand-core.h new file mode 100644 index 00000000000..6de20789a95 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/nand-core.h @@ -0,0 +1,28 @@ +/* arch/arm/plat-samsung/include/plat/nand-core.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S3C - Nand Controller core functions + * + * 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 __ASM_ARCH_NAND_CORE_H +#define __ASM_ARCH_NAND_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_nand_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_NAND + s3c_device_nand.name = name; +#endif +} + +#endif /* __ASM_ARCH_NAND_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/onenand-core.h b/arch/arm/plat-samsung/include/plat/onenand-core.h new file mode 100644 index 00000000000..7701cb7020c --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/onenand-core.h @@ -0,0 +1,37 @@ +/* + * linux/arch/arm/plat-samsung/onenand-core.h + * + * Copyright (c) 2010 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * Marek Szyprowski <m.szyprowski@samsung.com> + * + * Samsung OneNAD Controller core functions + * + * 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 __ASM_ARCH_ONENAND_CORE_H +#define __ASM_ARCH_ONENAND_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_onenand_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_ONENAND + s3c_device_onenand.name = name; +#endif +} + +static inline void s3c64xx_onenand1_setname(char *name) +{ +#ifdef CONFIG_S3C64XX_DEV_ONENAND1 + s3c64xx_device_onenand1.name = name; +#endif +} + +#endif /* __ASM_ARCH_ONENAND_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/pll.h b/arch/arm/plat-samsung/include/plat/pll.h new file mode 100644 index 00000000000..357af7c1c66 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pll.h @@ -0,0 +1,323 @@ +/* linux/arch/arm/plat-samsung/include/plat/pll.h + * + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Samsung PLL codes + * + * 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 <asm/div64.h> + +#define S3C24XX_PLL_MDIV_MASK (0xFF) +#define S3C24XX_PLL_PDIV_MASK (0x1F) +#define S3C24XX_PLL_SDIV_MASK (0x3) +#define S3C24XX_PLL_MDIV_SHIFT (12) +#define S3C24XX_PLL_PDIV_SHIFT (4) +#define S3C24XX_PLL_SDIV_SHIFT (0) + +static inline unsigned int s3c24xx_get_pll(unsigned int pllval, + unsigned int baseclk) +{ + unsigned int mdiv, pdiv, sdiv; + uint64_t fvco; + + mdiv = (pllval >> S3C24XX_PLL_MDIV_SHIFT) & S3C24XX_PLL_MDIV_MASK; + pdiv = (pllval >> S3C24XX_PLL_PDIV_SHIFT) & S3C24XX_PLL_PDIV_MASK; + sdiv = (pllval >> S3C24XX_PLL_SDIV_SHIFT) & S3C24XX_PLL_SDIV_MASK; + + fvco = (uint64_t)baseclk * (mdiv + 8); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned int)fvco; +} + +#define S3C2416_PLL_MDIV_MASK (0x3FF) +#define S3C2416_PLL_PDIV_MASK (0x3F) +#define S3C2416_PLL_SDIV_MASK (0x7) +#define S3C2416_PLL_MDIV_SHIFT (14) +#define S3C2416_PLL_PDIV_SHIFT (5) +#define S3C2416_PLL_SDIV_SHIFT (0) + +static inline unsigned int s3c2416_get_pll(unsigned int pllval, + unsigned int baseclk) +{ + unsigned int mdiv, pdiv, sdiv; + uint64_t fvco; + + mdiv = (pllval >> S3C2416_PLL_MDIV_SHIFT) & S3C2416_PLL_MDIV_MASK; + pdiv = (pllval >> S3C2416_PLL_PDIV_SHIFT) & S3C2416_PLL_PDIV_MASK; + sdiv = (pllval >> S3C2416_PLL_SDIV_SHIFT) & S3C2416_PLL_SDIV_MASK; + + fvco = (uint64_t)baseclk * mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned int)fvco; +} + +#define S3C6400_PLL_MDIV_MASK (0x3FF) +#define S3C6400_PLL_PDIV_MASK (0x3F) +#define S3C6400_PLL_SDIV_MASK (0x7) +#define S3C6400_PLL_MDIV_SHIFT (16) +#define S3C6400_PLL_PDIV_SHIFT (8) +#define S3C6400_PLL_SDIV_SHIFT (0) + +static inline unsigned long s3c6400_get_pll(unsigned long baseclk, + u32 pllcon) +{ + u32 mdiv, pdiv, sdiv; + u64 fvco = baseclk; + + mdiv = (pllcon >> S3C6400_PLL_MDIV_SHIFT) & S3C6400_PLL_MDIV_MASK; + pdiv = (pllcon >> S3C6400_PLL_PDIV_SHIFT) & S3C6400_PLL_PDIV_MASK; + sdiv = (pllcon >> S3C6400_PLL_SDIV_SHIFT) & S3C6400_PLL_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +#define PLL6553X_MDIV_MASK (0x7F) +#define PLL6553X_PDIV_MASK (0x1F) +#define PLL6553X_SDIV_MASK (0x3) +#define PLL6553X_KDIV_MASK (0xFFFF) +#define PLL6553X_MDIV_SHIFT (16) +#define PLL6553X_PDIV_SHIFT (8) +#define PLL6553X_SDIV_SHIFT (0) + +static inline unsigned long s3c_get_pll6553x(unsigned long baseclk, + u32 pll_con0, u32 pll_con1) +{ + unsigned long result; + u32 mdiv, pdiv, sdiv, kdiv; + u64 tmp; + + mdiv = (pll_con0 >> PLL6553X_MDIV_SHIFT) & PLL6553X_MDIV_MASK; + pdiv = (pll_con0 >> PLL6553X_PDIV_SHIFT) & PLL6553X_PDIV_MASK; + sdiv = (pll_con0 >> PLL6553X_SDIV_SHIFT) & PLL6553X_SDIV_MASK; + kdiv = pll_con1 & PLL6553X_KDIV_MASK; + + /* + * We need to multiple baseclk by mdiv (the integer part) and kdiv + * which is in 2^16ths, so shift mdiv up (does not overflow) and + * add kdiv before multiplying. The use of tmp is to avoid any + * overflows before shifting bac down into result when multipling + * by the mdiv and kdiv pair. + */ + + tmp = baseclk; + tmp *= (mdiv << 16) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 16; + + return result; +} + +#define PLL35XX_MDIV_MASK (0x3FF) +#define PLL35XX_PDIV_MASK (0x3F) +#define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_MDIV_SHIFT (16) +#define PLL35XX_PDIV_SHIFT (8) +#define PLL35XX_SDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll35xx(unsigned long baseclk, u32 pll_con) +{ + u32 mdiv, pdiv, sdiv; + u64 fvco = baseclk; + + mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK; + pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK; + sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +#define PLL36XX_KDIV_MASK (0xFFFF) +#define PLL36XX_MDIV_MASK (0x1FF) +#define PLL36XX_PDIV_MASK (0x3F) +#define PLL36XX_SDIV_MASK (0x7) +#define PLL36XX_MDIV_SHIFT (16) +#define PLL36XX_PDIV_SHIFT (8) +#define PLL36XX_SDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll36xx(unsigned long baseclk, + u32 pll_con0, u32 pll_con1) +{ + unsigned long result; + u32 mdiv, pdiv, sdiv, kdiv; + u64 tmp; + + mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK; + kdiv = pll_con1 & PLL36XX_KDIV_MASK; + + tmp = baseclk; + + tmp *= (mdiv << 16) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 16; + + return result; +} + +#define PLL45XX_MDIV_MASK (0x3FF) +#define PLL45XX_PDIV_MASK (0x3F) +#define PLL45XX_SDIV_MASK (0x7) +#define PLL45XX_MDIV_SHIFT (16) +#define PLL45XX_PDIV_SHIFT (8) +#define PLL45XX_SDIV_SHIFT (0) + +enum pll45xx_type_t { + pll_4500, + pll_4502, + pll_4508 +}; + +static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con, + enum pll45xx_type_t pll_type) +{ + u32 mdiv, pdiv, sdiv; + u64 fvco = baseclk; + + mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK; + pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK; + sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK; + + if (pll_type == pll_4508) + sdiv = sdiv - 1; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +/* CON0 bit-fields */ +#define PLL46XX_MDIV_MASK (0x1FF) +#define PLL46XX_PDIV_MASK (0x3F) +#define PLL46XX_SDIV_MASK (0x7) +#define PLL46XX_LOCKED_SHIFT (29) +#define PLL46XX_MDIV_SHIFT (16) +#define PLL46XX_PDIV_SHIFT (8) +#define PLL46XX_SDIV_SHIFT (0) + +/* CON1 bit-fields */ +#define PLL46XX_MRR_MASK (0x1F) +#define PLL46XX_MFR_MASK (0x3F) +#define PLL46XX_KDIV_MASK (0xFFFF) +#define PLL4650C_KDIV_MASK (0xFFF) +#define PLL46XX_MRR_SHIFT (24) +#define PLL46XX_MFR_SHIFT (16) +#define PLL46XX_KDIV_SHIFT (0) + +enum pll46xx_type_t { + pll_4600, + pll_4650, + pll_4650c, +}; + +static inline unsigned long s5p_get_pll46xx(unsigned long baseclk, + u32 pll_con0, u32 pll_con1, + enum pll46xx_type_t pll_type) +{ + unsigned long result; + u32 mdiv, pdiv, sdiv, kdiv; + u64 tmp; + + mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK; + kdiv = pll_con1 & PLL46XX_KDIV_MASK; + + if (pll_type == pll_4650c) + kdiv = pll_con1 & PLL4650C_KDIV_MASK; + else + kdiv = pll_con1 & PLL46XX_KDIV_MASK; + + tmp = baseclk; + + if (pll_type == pll_4600) { + tmp *= (mdiv << 16) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 16; + } else { + tmp *= (mdiv << 10) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 10; + } + + return result; +} + +#define PLL90XX_MDIV_MASK (0xFF) +#define PLL90XX_PDIV_MASK (0x3F) +#define PLL90XX_SDIV_MASK (0x7) +#define PLL90XX_KDIV_MASK (0xffff) +#define PLL90XX_LOCKED_SHIFT (29) +#define PLL90XX_MDIV_SHIFT (16) +#define PLL90XX_PDIV_SHIFT (8) +#define PLL90XX_SDIV_SHIFT (0) +#define PLL90XX_KDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll90xx(unsigned long baseclk, + u32 pll_con, u32 pll_conk) +{ + unsigned long result; + u32 mdiv, pdiv, sdiv, kdiv; + u64 tmp; + + mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK; + pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK; + sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK; + kdiv = pll_conk & PLL90XX_KDIV_MASK; + + /* + * We need to multiple baseclk by mdiv (the integer part) and kdiv + * which is in 2^16ths, so shift mdiv up (does not overflow) and + * add kdiv before multiplying. The use of tmp is to avoid any + * overflows before shifting bac down into result when multipling + * by the mdiv and kdiv pair. + */ + + tmp = baseclk; + tmp *= (mdiv << 16) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 16; + + return result; +} + +#define PLL65XX_MDIV_MASK (0x3FF) +#define PLL65XX_PDIV_MASK (0x3F) +#define PLL65XX_SDIV_MASK (0x7) +#define PLL65XX_MDIV_SHIFT (16) +#define PLL65XX_PDIV_SHIFT (8) +#define PLL65XX_SDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con) +{ + u32 mdiv, pdiv, sdiv; + u64 fvco = baseclk; + + mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK; + pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK; + sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h new file mode 100644 index 00000000000..8705f9e0e28 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pm-common.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa <t.figa@samsung.com> + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written by Ben Dooks, <ben@simtec.co.uk> + * + * 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 __PLAT_SAMSUNG_PM_COMMON_H +#define __PLAT_SAMSUNG_PM_COMMON_H __FILE__ + +#include <linux/irq.h> + +/* sleep save info */ + +/** + * struct sleep_save - save information for shared peripherals. + * @reg: Pointer to the register to save. + * @val: Holder for the value saved from reg. + * + * This describes a list of registers which is used by the pm core and + * other subsystem to save and restore register values over suspend. + */ +struct sleep_save { + void __iomem *reg; + unsigned long val; +}; + +#define SAVE_ITEM(x) \ + { .reg = (x) } + +/* helper functions to save/restore lists of registers. */ + +extern void s3c_pm_do_save(struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count); + +/* PM debug functions */ + +/** + * struct pm_uart_save - save block for core UART + * @ulcon: Save value for S3C2410_ULCON + * @ucon: Save value for S3C2410_UCON + * @ufcon: Save value for S3C2410_UFCON + * @umcon: Save value for S3C2410_UMCON + * @ubrdiv: Save value for S3C2410_UBRDIV + * + * Save block for UART registers to be held over sleep and restored if they + * are needed (say by debug). +*/ +struct pm_uart_save { + u32 ulcon; + u32 ucon; + u32 ufcon; + u32 umcon; + u32 ubrdiv; + u32 udivslot; +}; + +#ifdef CONFIG_SAMSUNG_PM_DEBUG +/** + * s3c_pm_dbg() - low level debug function for use in suspend/resume. + * @msg: The message to print. + * + * This function is used mainly to debug the resume process before the system + * can rely on printk/console output. It uses the low-level debugging output + * routine printascii() to do its work. + */ +extern void s3c_pm_dbg(const char *msg, ...); + +/** + * s3c_pm_debug_init() - suspend/resume low level debug initialization. + * @base: Virtual base of UART to use for suspend/resume debugging. + * + * This function needs to be called before S3C_PMDBG() can be used, to set up + * UART port base address and configuration. + */ +extern void s3c_pm_debug_init(void); + +#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt) + +extern void s3c_pm_save_uarts(void); +extern void s3c_pm_restore_uarts(void); +#else +#define S3C_PMDBG(fmt...) pr_debug(fmt) +#define s3c_pm_debug_init() do { } while (0) + +static inline void s3c_pm_save_uarts(void) { } +static inline void s3c_pm_restore_uarts(void) { } +#endif + +/* suspend memory checking */ + +#ifdef CONFIG_SAMSUNG_PM_CHECK +extern void s3c_pm_check_prepare(void); +extern void s3c_pm_check_restore(void); +extern void s3c_pm_check_cleanup(void); +extern void s3c_pm_check_store(void); +#else +#define s3c_pm_check_prepare() do { } while (0) +#define s3c_pm_check_restore() do { } while (0) +#define s3c_pm_check_cleanup() do { } while (0) +#define s3c_pm_check_store() do { } while (0) +#endif + +#endif diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h new file mode 100644 index 00000000000..e17d871b934 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -0,0 +1,113 @@ +/* arch/arm/plat-samsung/include/plat/pm.h + * + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written by Ben Dooks, <ben@simtec.co.uk> + * + * 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. +*/ + +/* s3c_pm_init + * + * called from board at initialisation time to setup the power + * management +*/ + +#include <plat/pm-common.h> + +struct device; + +#ifdef CONFIG_SAMSUNG_PM + +extern __init int s3c_pm_init(void); +extern __init int s3c64xx_pm_init(void); + +#else + +static inline int s3c_pm_init(void) +{ + return 0; +} + +static inline int s3c64xx_pm_init(void) +{ + return 0; +} +#endif + +/* configuration for the IRQ mask over sleep */ +extern unsigned long s3c_irqwake_intmask; +extern unsigned long s3c_irqwake_eintmask; + +/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */ +extern unsigned long s3c_irqwake_intallow; +extern unsigned long s3c_irqwake_eintallow; + +/* per-cpu sleep functions */ + +extern void (*pm_cpu_prep)(void); +extern int (*pm_cpu_sleep)(unsigned long); + +/* Flags for PM Control */ + +extern unsigned long s3c_pm_flags; + +/* from sleep.S */ + +extern int s3c2410_cpu_suspend(unsigned long); + +#ifdef CONFIG_SAMSUNG_PM +extern int s3c_irq_wake(struct irq_data *data, unsigned int state); +extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); +extern void s3c_cpu_resume(void); +#else +#define s3c_irq_wake NULL +#define s3c_irqext_wake NULL +#define s3c_cpu_resume NULL +#endif + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +/** + * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs + * @set: set bits for the state of the LEDs + * @clear: clear bits for the state of the LEDs. + */ +extern void s3c_pm_debug_smdkled(u32 set, u32 clear); + +#else +static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { } +#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */ + +/** + * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ + * + * Setup all the necessary GPIO pins for waking the system on external + * interrupt. + */ +extern void s3c_pm_configure_extint(void); + +#ifdef CONFIG_GPIO_SAMSUNG +/** + * samsung_pm_restore_gpios() - restore the state of the gpios after sleep. + * + * Restore the state of the GPIO pins after sleep, which may involve ensuring + * that we do not glitch the state of the pins from that the bootloader's + * resume code has done. +*/ +extern void samsung_pm_restore_gpios(void); + +/** + * samsung_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. + * + * Save the GPIO states for resotration on resume. See samsung_pm_restore_gpios(). + */ +extern void samsung_pm_save_gpios(void); +#else +static inline void samsung_pm_restore_gpios(void) {} +static inline void samsung_pm_save_gpios(void) {} +#endif + +extern void s3c_pm_save_core(void); +extern void s3c_pm_restore_core(void); diff --git a/arch/arm/plat-samsung/include/plat/pwm-core.h b/arch/arm/plat-samsung/include/plat/pwm-core.h new file mode 100644 index 00000000000..5bff1facb67 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pwm-core.h @@ -0,0 +1,22 @@ +/* + * Copyright 2013 Tomasz Figa <tomasz.figa@gmail.com> + * + * Samsung PWM controller platform data helpers. + * + * 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 __ASM_ARCH_PWM_CORE_H +#define __ASM_ARCH_PWM_CORE_H __FILE__ + +#include <clocksource/samsung_pwm.h> + +#ifdef CONFIG_SAMSUNG_DEV_PWM +extern void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd); +#else +static inline void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd) { } +#endif + +#endif /* __ASM_ARCH_PWM_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/regs-adc.h b/arch/arm/plat-samsung/include/plat/regs-adc.h new file mode 100644 index 00000000000..70612100120 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-adc.h @@ -0,0 +1,68 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-adc.h + * + * Copyright (c) 2004 Shannon Holland <holland@loser.net> + * + * This program is free software; yosu 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. + * + * S3C2410 ADC registers +*/ + +#ifndef __ASM_ARCH_REGS_ADC_H +#define __ASM_ARCH_REGS_ADC_H "regs-adc.h" + +#define S3C2410_ADCREG(x) (x) + +#define S3C2410_ADCCON S3C2410_ADCREG(0x00) +#define S3C2410_ADCTSC S3C2410_ADCREG(0x04) +#define S3C2410_ADCDLY S3C2410_ADCREG(0x08) +#define S3C2410_ADCDAT0 S3C2410_ADCREG(0x0C) +#define S3C2410_ADCDAT1 S3C2410_ADCREG(0x10) +#define S3C64XX_ADCUPDN S3C2410_ADCREG(0x14) +#define S3C2443_ADCMUX S3C2410_ADCREG(0x18) +#define S3C64XX_ADCCLRINT S3C2410_ADCREG(0x18) +#define S5P_ADCMUX S3C2410_ADCREG(0x1C) +#define S3C64XX_ADCCLRINTPNDNUP S3C2410_ADCREG(0x20) + + +/* ADCCON Register Bits */ +#define S3C64XX_ADCCON_RESSEL (1<<16) +#define S3C2410_ADCCON_ECFLG (1<<15) +#define S3C2410_ADCCON_PRSCEN (1<<14) +#define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6) +#define S3C2410_ADCCON_PRSCVLMASK (0xFF<<6) +#define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3) +#define S3C2410_ADCCON_MUXMASK (0x7<<3) +#define S3C2416_ADCCON_RESSEL (1 << 3) +#define S3C2410_ADCCON_STDBM (1<<2) +#define S3C2410_ADCCON_READ_START (1<<1) +#define S3C2410_ADCCON_ENABLE_START (1<<0) +#define S3C2410_ADCCON_STARTMASK (0x3<<0) + + +/* ADCTSC Register Bits */ +#define S3C2443_ADCTSC_UD_SEN (1 << 8) +#define S3C2410_ADCTSC_YM_SEN (1<<7) +#define S3C2410_ADCTSC_YP_SEN (1<<6) +#define S3C2410_ADCTSC_XM_SEN (1<<5) +#define S3C2410_ADCTSC_XP_SEN (1<<4) +#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) +#define S3C2410_ADCTSC_AUTO_PST (1<<2) +#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) + +/* ADCDAT0 Bits */ +#define S3C2410_ADCDAT0_UPDOWN (1<<15) +#define S3C2410_ADCDAT0_AUTO_PST (1<<14) +#define S3C2410_ADCDAT0_XY_PST (0x3<<12) +#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) + +/* ADCDAT1 Bits */ +#define S3C2410_ADCDAT1_UPDOWN (1<<15) +#define S3C2410_ADCDAT1_AUTO_PST (1<<14) +#define S3C2410_ADCDAT1_XY_PST (0x3<<12) +#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) + +#endif /* __ASM_ARCH_REGS_ADC_H */ + + diff --git a/arch/arm/plat-samsung/include/plat/regs-dma.h b/arch/arm/plat-samsung/include/plat/regs-dma.h new file mode 100644 index 00000000000..a7d622ef16a --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-dma.h @@ -0,0 +1,151 @@ +/* arch/arm/plat-samsung/include/plat/regs-dma.h + * + * Copyright (C) 2003-2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C24XX DMA support + * + * 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 __ASM_PLAT_REGS_DMA_H +#define __ASM_PLAT_REGS_DMA_H __FILE__ + +#define S3C2410_DMA_DISRC (0x00) +#define S3C2410_DMA_DISRCC (0x04) +#define S3C2410_DMA_DIDST (0x08) +#define S3C2410_DMA_DIDSTC (0x0C) +#define S3C2410_DMA_DCON (0x10) +#define S3C2410_DMA_DSTAT (0x14) +#define S3C2410_DMA_DCSRC (0x18) +#define S3C2410_DMA_DCDST (0x1C) +#define S3C2410_DMA_DMASKTRIG (0x20) +#define S3C2412_DMA_DMAREQSEL (0x24) +#define S3C2443_DMA_DMAREQSEL (0x24) + +#define S3C2410_DISRCC_INC (1 << 0) +#define S3C2410_DISRCC_APB (1 << 1) + +#define S3C2410_DMASKTRIG_STOP (1 << 2) +#define S3C2410_DMASKTRIG_ON (1 << 1) +#define S3C2410_DMASKTRIG_SWTRIG (1 << 0) + +#define S3C2410_DCON_DEMAND (0 << 31) +#define S3C2410_DCON_HANDSHAKE (1 << 31) +#define S3C2410_DCON_SYNC_PCLK (0 << 30) +#define S3C2410_DCON_SYNC_HCLK (1 << 30) + +#define S3C2410_DCON_INTREQ (1 << 29) + +#define S3C2410_DCON_CH0_XDREQ0 (0 << 24) +#define S3C2410_DCON_CH0_UART0 (1 << 24) +#define S3C2410_DCON_CH0_SDI (2 << 24) +#define S3C2410_DCON_CH0_TIMER (3 << 24) +#define S3C2410_DCON_CH0_USBEP1 (4 << 24) + +#define S3C2410_DCON_CH1_XDREQ1 (0 << 24) +#define S3C2410_DCON_CH1_UART1 (1 << 24) +#define S3C2410_DCON_CH1_I2SSDI (2 << 24) +#define S3C2410_DCON_CH1_SPI (3 << 24) +#define S3C2410_DCON_CH1_USBEP2 (4 << 24) + +#define S3C2410_DCON_CH2_I2SSDO (0 << 24) +#define S3C2410_DCON_CH2_I2SSDI (1 << 24) +#define S3C2410_DCON_CH2_SDI (2 << 24) +#define S3C2410_DCON_CH2_TIMER (3 << 24) +#define S3C2410_DCON_CH2_USBEP3 (4 << 24) + +#define S3C2410_DCON_CH3_UART2 (0 << 24) +#define S3C2410_DCON_CH3_SDI (1 << 24) +#define S3C2410_DCON_CH3_SPI (2 << 24) +#define S3C2410_DCON_CH3_TIMER (3 << 24) +#define S3C2410_DCON_CH3_USBEP4 (4 << 24) + +#define S3C2410_DCON_SRCSHIFT (24) +#define S3C2410_DCON_SRCMASK (7 << 24) + +#define S3C2410_DCON_BYTE (0 << 20) +#define S3C2410_DCON_HALFWORD (1 << 20) +#define S3C2410_DCON_WORD (2 << 20) + +#define S3C2410_DCON_AUTORELOAD (0 << 22) +#define S3C2410_DCON_NORELOAD (1 << 22) +#define S3C2410_DCON_HWTRIG (1 << 23) + +#ifdef CONFIG_CPU_S3C2440 + +#define S3C2440_DIDSTC_CHKINT (1 << 2) + +#define S3C2440_DCON_CH0_I2SSDO (5 << 24) +#define S3C2440_DCON_CH0_PCMIN (6 << 24) + +#define S3C2440_DCON_CH1_PCMOUT (5 << 24) +#define S3C2440_DCON_CH1_SDI (6 << 24) + +#define S3C2440_DCON_CH2_PCMIN (5 << 24) +#define S3C2440_DCON_CH2_MICIN (6 << 24) + +#define S3C2440_DCON_CH3_MICIN (5 << 24) +#define S3C2440_DCON_CH3_PCMOUT (6 << 24) +#endif /* CONFIG_CPU_S3C2440 */ + +#ifdef CONFIG_CPU_S3C2412 + +#define S3C2412_DMAREQSEL_SRC(x) ((x) << 1) + +#define S3C2412_DMAREQSEL_HW (1) + +#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0) +#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1) +#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2) +#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3) +#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4) +#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5) +#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9) +#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10) +#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13) +#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14) +#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15) +#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16) +#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17) +#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18) +#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19) +#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20) +#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21) +#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22) +#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23) +#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24) +#endif /* CONFIG_CPU_S3C2412 */ + +#if defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2443) + +#define S3C2443_DMAREQSEL_SRC(x) ((x) << 1) + +#define S3C2443_DMAREQSEL_HW (1) + +#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0) +#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1) +#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2) +#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3) +#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4) +#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5) +#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9) +#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10) +#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17) +#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18) +#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19) +#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20) +#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21) +#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22) +#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23) +#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24) +#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25) +#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26) +#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27) +#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28) +#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29) +#endif /* CONFIG_CPU_S3C2443 */ + +#endif /* __ASM_PLAT_REGS_DMA_H */ diff --git a/arch/arm/plat-samsung/include/plat/regs-irqtype.h b/arch/arm/plat-samsung/include/plat/regs-irqtype.h new file mode 100644 index 00000000000..c63cd3fc5ad --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-irqtype.h @@ -0,0 +1,21 @@ +/* arch/arm/plat-s3c/include/plat/regs-irqtype.h + * + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C - IRQ detection types. + * + * 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. + */ + +/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including + * the S3C64XX +*/ +#define S3C2410_EXTINT_LOWLEV (0x00) +#define S3C2410_EXTINT_HILEV (0x01) +#define S3C2410_EXTINT_FALLEDGE (0x02) +#define S3C2410_EXTINT_RISEEDGE (0x04) +#define S3C2410_EXTINT_BOTHEDGE (0x06) diff --git a/arch/arm/plat-samsung/include/plat/regs-spi.h b/arch/arm/plat-samsung/include/plat/regs-spi.h new file mode 100644 index 00000000000..552fe7cfe28 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-spi.h @@ -0,0 +1,48 @@ +/* arch/arm/plat-samsung/include/plat/regs-spi.h + * + * Copyright (c) 2004 Fetron GmbH + * + * 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. + * + * S3C2410 SPI register definition +*/ + +#ifndef __ASM_ARCH_REGS_SPI_H +#define __ASM_ARCH_REGS_SPI_H + +#define S3C2410_SPI1 (0x20) +#define S3C2412_SPI1 (0x100) + +#define S3C2410_SPCON (0x00) + +#define S3C2410_SPCON_SMOD_DMA (2 << 5) /* DMA mode */ +#define S3C2410_SPCON_SMOD_INT (1 << 5) /* interrupt mode */ +#define S3C2410_SPCON_SMOD_POLL (0 << 5) /* polling mode */ +#define S3C2410_SPCON_ENSCK (1 << 4) /* Enable SCK */ +#define S3C2410_SPCON_MSTR (1 << 3) /* Master:1, Slave:0 select */ +#define S3C2410_SPCON_CPOL_HIGH (1 << 2) /* Clock polarity select */ +#define S3C2410_SPCON_CPOL_LOW (0 << 2) /* Clock polarity select */ + +#define S3C2410_SPCON_CPHA_FMTB (1 << 1) /* Clock Phase Select */ +#define S3C2410_SPCON_CPHA_FMTA (0 << 1) /* Clock Phase Select */ + +#define S3C2410_SPSTA (0x04) + +#define S3C2410_SPSTA_DCOL (1 << 2) /* Data Collision Error */ +#define S3C2410_SPSTA_MULD (1 << 1) /* Multi Master Error */ +#define S3C2410_SPSTA_READY (1 << 0) /* Data Tx/Rx ready */ +#define S3C2412_SPSTA_READY_ORG (1 << 3) + +#define S3C2410_SPPIN (0x08) + +#define S3C2410_SPPIN_ENMUL (1 << 2) /* Multi Master Error detect */ +#define S3C2410_SPPIN_RESERVED (1 << 1) +#define S3C2410_SPPIN_KEEP (1 << 0) /* Master Out keep */ + +#define S3C2410_SPPRE (0x0C) +#define S3C2410_SPTDAT (0x10) +#define S3C2410_SPRDAT (0x14) + +#endif /* __ASM_ARCH_REGS_SPI_H */ diff --git a/arch/arm/plat-samsung/include/plat/regs-srom.h b/arch/arm/plat-samsung/include/plat/regs-srom.h new file mode 100644 index 00000000000..9b6729c81cd --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-srom.h @@ -0,0 +1,54 @@ +/* linux/arch/arm/plat-samsung/include/plat/regs-srom.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5P SROMC register definitions + * + * 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 __PLAT_SAMSUNG_REGS_SROM_H +#define __PLAT_SAMSUNG_REGS_SROM_H __FILE__ + +#include <mach/map.h> + +#define S5P_SROMREG(x) (S5P_VA_SROMC + (x)) + +#define S5P_SROM_BW S5P_SROMREG(0x0) +#define S5P_SROM_BC0 S5P_SROMREG(0x4) +#define S5P_SROM_BC1 S5P_SROMREG(0x8) +#define S5P_SROM_BC2 S5P_SROMREG(0xc) +#define S5P_SROM_BC3 S5P_SROMREG(0x10) +#define S5P_SROM_BC4 S5P_SROMREG(0x14) +#define S5P_SROM_BC5 S5P_SROMREG(0x18) + +/* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */ + +#define S5P_SROM_BW__DATAWIDTH__SHIFT 0 +#define S5P_SROM_BW__ADDRMODE__SHIFT 1 +#define S5P_SROM_BW__WAITENABLE__SHIFT 2 +#define S5P_SROM_BW__BYTEENABLE__SHIFT 3 + +#define S5P_SROM_BW__CS_MASK 0xf + +#define S5P_SROM_BW__NCS0__SHIFT 0 +#define S5P_SROM_BW__NCS1__SHIFT 4 +#define S5P_SROM_BW__NCS2__SHIFT 8 +#define S5P_SROM_BW__NCS3__SHIFT 12 +#define S5P_SROM_BW__NCS4__SHIFT 16 +#define S5P_SROM_BW__NCS5__SHIFT 20 + +/* applies to same to BCS0 - BCS3 */ + +#define S5P_SROM_BCX__PMC__SHIFT 0 +#define S5P_SROM_BCX__TACP__SHIFT 4 +#define S5P_SROM_BCX__TCAH__SHIFT 8 +#define S5P_SROM_BCX__TCOH__SHIFT 12 +#define S5P_SROM_BCX__TACC__SHIFT 16 +#define S5P_SROM_BCX__TCOS__SHIFT 24 +#define S5P_SROM_BCX__TACS__SHIFT 28 + +#endif /* __PLAT_SAMSUNG_REGS_SROM_H */ diff --git a/arch/arm/plat-samsung/include/plat/regs-udc.h b/arch/arm/plat-samsung/include/plat/regs-udc.h new file mode 100644 index 00000000000..4003d3dab4e --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-udc.h @@ -0,0 +1,151 @@ +/* arch/arm/plat-samsung/include/plat/regs-udc.h + * + * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at> + * + * This include file 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 __ASM_ARCH_REGS_UDC_H +#define __ASM_ARCH_REGS_UDC_H + +#define S3C2410_USBDREG(x) (x) + +#define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140) +#define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144) +#define S3C2410_UDC_EP_INT_REG S3C2410_USBDREG(0x0148) + +#define S3C2410_UDC_USB_INT_REG S3C2410_USBDREG(0x0158) +#define S3C2410_UDC_EP_INT_EN_REG S3C2410_USBDREG(0x015c) + +#define S3C2410_UDC_USB_INT_EN_REG S3C2410_USBDREG(0x016c) + +#define S3C2410_UDC_FRAME_NUM1_REG S3C2410_USBDREG(0x0170) +#define S3C2410_UDC_FRAME_NUM2_REG S3C2410_USBDREG(0x0174) + +#define S3C2410_UDC_EP0_FIFO_REG S3C2410_USBDREG(0x01c0) +#define S3C2410_UDC_EP1_FIFO_REG S3C2410_USBDREG(0x01c4) +#define S3C2410_UDC_EP2_FIFO_REG S3C2410_USBDREG(0x01c8) +#define S3C2410_UDC_EP3_FIFO_REG S3C2410_USBDREG(0x01cc) +#define S3C2410_UDC_EP4_FIFO_REG S3C2410_USBDREG(0x01d0) + +#define S3C2410_UDC_EP1_DMA_CON S3C2410_USBDREG(0x0200) +#define S3C2410_UDC_EP1_DMA_UNIT S3C2410_USBDREG(0x0204) +#define S3C2410_UDC_EP1_DMA_FIFO S3C2410_USBDREG(0x0208) +#define S3C2410_UDC_EP1_DMA_TTC_L S3C2410_USBDREG(0x020c) +#define S3C2410_UDC_EP1_DMA_TTC_M S3C2410_USBDREG(0x0210) +#define S3C2410_UDC_EP1_DMA_TTC_H S3C2410_USBDREG(0x0214) + +#define S3C2410_UDC_EP2_DMA_CON S3C2410_USBDREG(0x0218) +#define S3C2410_UDC_EP2_DMA_UNIT S3C2410_USBDREG(0x021c) +#define S3C2410_UDC_EP2_DMA_FIFO S3C2410_USBDREG(0x0220) +#define S3C2410_UDC_EP2_DMA_TTC_L S3C2410_USBDREG(0x0224) +#define S3C2410_UDC_EP2_DMA_TTC_M S3C2410_USBDREG(0x0228) +#define S3C2410_UDC_EP2_DMA_TTC_H S3C2410_USBDREG(0x022c) + +#define S3C2410_UDC_EP3_DMA_CON S3C2410_USBDREG(0x0240) +#define S3C2410_UDC_EP3_DMA_UNIT S3C2410_USBDREG(0x0244) +#define S3C2410_UDC_EP3_DMA_FIFO S3C2410_USBDREG(0x0248) +#define S3C2410_UDC_EP3_DMA_TTC_L S3C2410_USBDREG(0x024c) +#define S3C2410_UDC_EP3_DMA_TTC_M S3C2410_USBDREG(0x0250) +#define S3C2410_UDC_EP3_DMA_TTC_H S3C2410_USBDREG(0x0254) + +#define S3C2410_UDC_EP4_DMA_CON S3C2410_USBDREG(0x0258) +#define S3C2410_UDC_EP4_DMA_UNIT S3C2410_USBDREG(0x025c) +#define S3C2410_UDC_EP4_DMA_FIFO S3C2410_USBDREG(0x0260) +#define S3C2410_UDC_EP4_DMA_TTC_L S3C2410_USBDREG(0x0264) +#define S3C2410_UDC_EP4_DMA_TTC_M S3C2410_USBDREG(0x0268) +#define S3C2410_UDC_EP4_DMA_TTC_H S3C2410_USBDREG(0x026c) + +#define S3C2410_UDC_INDEX_REG S3C2410_USBDREG(0x0178) + +/* indexed registers */ + +#define S3C2410_UDC_MAXP_REG S3C2410_USBDREG(0x0180) + +#define S3C2410_UDC_EP0_CSR_REG S3C2410_USBDREG(0x0184) + +#define S3C2410_UDC_IN_CSR1_REG S3C2410_USBDREG(0x0184) +#define S3C2410_UDC_IN_CSR2_REG S3C2410_USBDREG(0x0188) + +#define S3C2410_UDC_OUT_CSR1_REG S3C2410_USBDREG(0x0190) +#define S3C2410_UDC_OUT_CSR2_REG S3C2410_USBDREG(0x0194) +#define S3C2410_UDC_OUT_FIFO_CNT1_REG S3C2410_USBDREG(0x0198) +#define S3C2410_UDC_OUT_FIFO_CNT2_REG S3C2410_USBDREG(0x019c) + +#define S3C2410_UDC_FUNCADDR_UPDATE (1 << 7) + +#define S3C2410_UDC_PWR_ISOUP (1 << 7) /* R/W */ +#define S3C2410_UDC_PWR_RESET (1 << 3) /* R */ +#define S3C2410_UDC_PWR_RESUME (1 << 2) /* R/W */ +#define S3C2410_UDC_PWR_SUSPEND (1 << 1) /* R */ +#define S3C2410_UDC_PWR_ENSUSPEND (1 << 0) /* R/W */ + +#define S3C2410_UDC_PWR_DEFAULT (0x00) + +#define S3C2410_UDC_INT_EP4 (1 << 4) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP3 (1 << 3) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP2 (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP1 (1 << 1) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP0 (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_USBINT_RESET (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_USBINT_RESUME (1 << 1) /* R/W (clear only) */ +#define S3C2410_UDC_USBINT_SUSPEND (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_INTE_EP4 (1 << 4) /* R/W */ +#define S3C2410_UDC_INTE_EP3 (1 << 3) /* R/W */ +#define S3C2410_UDC_INTE_EP2 (1 << 2) /* R/W */ +#define S3C2410_UDC_INTE_EP1 (1 << 1) /* R/W */ +#define S3C2410_UDC_INTE_EP0 (1 << 0) /* R/W */ + +#define S3C2410_UDC_USBINTE_RESET (1 << 2) /* R/W */ +#define S3C2410_UDC_USBINTE_SUSPEND (1 << 0) /* R/W */ + +#define S3C2410_UDC_INDEX_EP0 (0x00) +#define S3C2410_UDC_INDEX_EP1 (0x01) +#define S3C2410_UDC_INDEX_EP2 (0x02) +#define S3C2410_UDC_INDEX_EP3 (0x03) +#define S3C2410_UDC_INDEX_EP4 (0x04) + +#define S3C2410_UDC_ICSR1_CLRDT (1 << 6) /* R/W */ +#define S3C2410_UDC_ICSR1_SENTSTL (1 << 5) /* R/W (clear only) */ +#define S3C2410_UDC_ICSR1_SENDSTL (1 << 4) /* R/W */ +#define S3C2410_UDC_ICSR1_FFLUSH (1 << 3) /* W (set only) */ +#define S3C2410_UDC_ICSR1_UNDRUN (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_ICSR1_PKTRDY (1 << 0) /* R/W (set only) */ + +#define S3C2410_UDC_ICSR2_AUTOSET (1 << 7) /* R/W */ +#define S3C2410_UDC_ICSR2_ISO (1 << 6) /* R/W */ +#define S3C2410_UDC_ICSR2_MODEIN (1 << 5) /* R/W */ +#define S3C2410_UDC_ICSR2_DMAIEN (1 << 4) /* R/W */ + +#define S3C2410_UDC_OCSR1_CLRDT (1 << 7) /* R/W */ +#define S3C2410_UDC_OCSR1_SENTSTL (1 << 6) /* R/W (clear only) */ +#define S3C2410_UDC_OCSR1_SENDSTL (1 << 5) /* R/W */ +#define S3C2410_UDC_OCSR1_FFLUSH (1 << 4) /* R/W */ +#define S3C2410_UDC_OCSR1_DERROR (1 << 3) /* R */ +#define S3C2410_UDC_OCSR1_OVRRUN (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_OCSR1_PKTRDY (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_OCSR2_AUTOCLR (1 << 7) /* R/W */ +#define S3C2410_UDC_OCSR2_ISO (1 << 6) /* R/W */ +#define S3C2410_UDC_OCSR2_DMAIEN (1 << 5) /* R/W */ + +#define S3C2410_UDC_EP0_CSR_OPKRDY (1 << 0) +#define S3C2410_UDC_EP0_CSR_IPKRDY (1 << 1) +#define S3C2410_UDC_EP0_CSR_SENTSTL (1 << 2) +#define S3C2410_UDC_EP0_CSR_DE (1 << 3) +#define S3C2410_UDC_EP0_CSR_SE (1 << 4) +#define S3C2410_UDC_EP0_CSR_SENDSTL (1 << 5) +#define S3C2410_UDC_EP0_CSR_SOPKTRDY (1 << 6) +#define S3C2410_UDC_EP0_CSR_SSE (1 << 7) + +#define S3C2410_UDC_MAXP_8 (1 << 0) +#define S3C2410_UDC_MAXP_16 (1 << 1) +#define S3C2410_UDC_MAXP_32 (1 << 2) +#define S3C2410_UDC_MAXP_64 (1 << 3) + +#endif diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h new file mode 100644 index 00000000000..fcf27966206 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h @@ -0,0 +1,51 @@ +/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - USB2.0 Highspeed/OtG device PHY registers + * + * 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. +*/ + +/* Note, this is a separate header file as some of the clock framework + * needs to touch this if the clk_48m is used as the USB OHCI or other + * peripheral source. +*/ + +#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H +#define __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H __FILE__ + +/* S3C64XX_PA_USB_HSPHY */ + +#define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY) + +#define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00) +#define S3C_PHYPWR_NORMAL_MASK (0x19 << 0) +#define S3C_PHYPWR_OTG_DISABLE (1 << 4) +#define S3C_PHYPWR_ANALOG_POWERDOWN (1 << 3) +#define SRC_PHYPWR_FORCE_SUSPEND (1 << 1) + +#define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04) +#define S3C_PHYCLK_MODE_USB11 (1 << 6) +#define S3C_PHYCLK_EXT_OSC (1 << 5) +#define S3C_PHYCLK_CLK_FORCE (1 << 4) +#define S3C_PHYCLK_ID_PULL (1 << 2) +#define S3C_PHYCLK_CLKSEL_MASK (0x3 << 0) +#define S3C_PHYCLK_CLKSEL_SHIFT (0) +#define S3C_PHYCLK_CLKSEL_48M (0x0 << 0) +#define S3C_PHYCLK_CLKSEL_12M (0x2 << 0) +#define S3C_PHYCLK_CLKSEL_24M (0x3 << 0) + +#define S3C_RSTCON S3C_HSOTG_PHYREG(0x08) +#define S3C_RSTCON_PHYCLK (1 << 2) +#define S3C_RSTCON_HCLK (1 << 1) +#define S3C_RSTCON_PHY (1 << 0) + +#define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20) + +#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H */ diff --git a/arch/arm/plat-samsung/include/plat/s5p-clock.h b/arch/arm/plat-samsung/include/plat/s5p-clock.h new file mode 100644 index 00000000000..8364b4bea8b --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/s5p-clock.h @@ -0,0 +1,65 @@ +/* linux/arch/arm/plat-samsung/include/plat/s5p-clock.h + * + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Header file for s5p clock support + * + * 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 __ASM_PLAT_S5P_CLOCK_H +#define __ASM_PLAT_S5P_CLOCK_H __FILE__ + +#include <linux/clk.h> + +#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1) + +#define clk_fin_apll clk_ext_xtal_mux +#define clk_fin_bpll clk_ext_xtal_mux +#define clk_fin_cpll clk_ext_xtal_mux +#define clk_fin_mpll clk_ext_xtal_mux +#define clk_fin_epll clk_ext_xtal_mux +#define clk_fin_dpll clk_ext_xtal_mux +#define clk_fin_vpll clk_ext_xtal_mux +#define clk_fin_hpll clk_ext_xtal_mux + +extern struct clk clk_ext_xtal_mux; +extern struct clk clk_xusbxti; +extern struct clk clk_48m; +extern struct clk s5p_clk_27m; +extern struct clk clk_fout_apll; +extern struct clk clk_fout_bpll; +extern struct clk clk_fout_bpll_div2; +extern struct clk clk_fout_cpll; +extern struct clk clk_fout_mpll; +extern struct clk clk_fout_mpll_div2; +extern struct clk clk_fout_epll; +extern struct clk clk_fout_dpll; +extern struct clk clk_fout_vpll; +extern struct clk clk_arm; +extern struct clk clk_vpll; + +extern struct clksrc_sources clk_src_apll; +extern struct clksrc_sources clk_src_bpll; +extern struct clksrc_sources clk_src_bpll_fout; +extern struct clksrc_sources clk_src_cpll; +extern struct clksrc_sources clk_src_mpll; +extern struct clksrc_sources clk_src_mpll_fout; +extern struct clksrc_sources clk_src_epll; +extern struct clksrc_sources clk_src_dpll; + +extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable); + +/* Common EPLL operations for S5P platform */ +extern int s5p_epll_enable(struct clk *clk, int enable); +extern unsigned long s5p_epll_get_rate(struct clk *clk); + +/* SPDIF clk operations common for S5PC100/V210/C110 and Exynos4 */ +extern int s5p_spdif_set_rate(struct clk *clk, unsigned long rate); +extern unsigned long s5p_spdif_get_rate(struct clk *clk); + +extern struct clk_ops s5p_sclk_spdif_ops; +#endif /* __ASM_PLAT_S5P_CLOCK_H */ diff --git a/arch/arm/plat-samsung/include/plat/samsung-time.h b/arch/arm/plat-samsung/include/plat/samsung-time.h new file mode 100644 index 00000000000..209464adef9 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/samsung-time.h @@ -0,0 +1,30 @@ +/* linux/arch/arm/plat-samsung/include/plat/samsung-time.h + * + * Copyright 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for samsung s3c and s5p time support + * + * 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 __ASM_PLAT_SAMSUNG_TIME_H +#define __ASM_PLAT_SAMSUNG_TIME_H __FILE__ + +/* SAMSUNG HR-Timer Clock mode */ +enum samsung_timer_mode { + SAMSUNG_PWM0, + SAMSUNG_PWM1, + SAMSUNG_PWM2, + SAMSUNG_PWM3, + SAMSUNG_PWM4, +}; + +extern void __init samsung_set_timer_source(enum samsung_timer_mode event, + enum samsung_timer_mode source); + +extern void __init samsung_timer_init(void); + +#endif /* __ASM_PLAT_SAMSUNG_TIME_H */ diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h new file mode 100644 index 00000000000..bf650218b40 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/sdhci.h @@ -0,0 +1,290 @@ +/* linux/arch/arm/plat-samsung/include/plat/sdhci.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - SDHCI (HSMMC) platform data definitions + * + * 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 __PLAT_S3C_SDHCI_H +#define __PLAT_S3C_SDHCI_H __FILE__ + +#include <linux/platform_data/mmc-sdhci-s3c.h> +#include <plat/devs.h> + +/* s3c_sdhci_set_platdata() - common helper for setting SDHCI platform data + * @pd: The default platform data for this device. + * @set: Pointer to the platform data to fill in. + */ +extern void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, + struct s3c_sdhci_platdata *set); + +/** + * s3c_sdhci0_set_platdata - Set platform data for S3C SDHCI device. + * @pd: Platform data to register to device. + * + * Register the given platform data for use withe S3C SDHCI device. + * The call will copy the platform data, so the board definitions can + * make the structure itself __initdata. + */ +extern void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd); + +/* Default platform data, exported so that per-cpu initialisation can + * set the correct one when there are more than one cpu type selected. +*/ + +extern struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata; + +/* Helper function availability */ + +extern void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *, int w); +extern void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w); +extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w); +extern void exynos4_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void exynos4_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void exynos4_setup_sdhci2_cfg_gpio(struct platform_device *, int w); +extern void exynos4_setup_sdhci3_cfg_gpio(struct platform_device *, int w); +extern void s5p64x0_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s5p64x0_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s5p6440_setup_sdhci2_cfg_gpio(struct platform_device *, int w); +extern void s5p6450_setup_sdhci2_cfg_gpio(struct platform_device *, int w); + +/* S3C2416 SDHCI setup */ + +#ifdef CONFIG_S3C2416_SETUP_SDHCI +static inline void s3c2416_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c2416_setup_sdhci0_cfg_gpio; +#endif /* CONFIG_S3C_DEV_HSMMC */ +} + +static inline void s3c2416_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c2416_setup_sdhci1_cfg_gpio; +#endif /* CONFIG_S3C_DEV_HSMMC1 */ +} + +#else +static inline void s3c2416_default_sdhci0(void) { } +static inline void s3c2416_default_sdhci1(void) { } + +#endif /* CONFIG_S3C2416_SETUP_SDHCI */ + +/* S3C64XX SDHCI setup */ + +#ifdef CONFIG_S3C64XX_SETUP_SDHCI +static inline void s3c6400_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s3c6400_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s3c6400_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; +#endif +} + +#else +static inline void s3c6410_default_sdhci0(void) { } +static inline void s3c6410_default_sdhci1(void) { } +static inline void s3c6410_default_sdhci2(void) { } +static inline void s3c6400_default_sdhci0(void) { } +static inline void s3c6400_default_sdhci1(void) { } +static inline void s3c6400_default_sdhci2(void) { } + +#endif /* CONFIG_S3C64XX_SETUP_SDHCI */ + +/* S5P64X0 SDHCI setup */ + +#ifdef CONFIG_S5P64X0_SETUP_SDHCI_GPIO +static inline void s5p64x0_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s5p64x0_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s5p64x0_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s5p64x0_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s5p6440_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s5p6440_setup_sdhci2_cfg_gpio; +#endif +} + +static inline void s5p6450_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s5p6450_setup_sdhci2_cfg_gpio; +#endif +} + +#else +static inline void s5p64x0_default_sdhci0(void) { } +static inline void s5p64x0_default_sdhci1(void) { } +static inline void s5p6440_default_sdhci2(void) { } +static inline void s5p6450_default_sdhci2(void) { } + +#endif /* CONFIG_S5P64X0_SETUP_SDHCI_GPIO */ + +/* S5PC100 SDHCI setup */ + +#ifdef CONFIG_S5PC100_SETUP_SDHCI +static inline void s5pc100_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s5pc100_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s5pc100_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s5pc100_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s5pc100_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s5pc100_setup_sdhci2_cfg_gpio; +#endif +} + +#else +static inline void s5pc100_default_sdhci0(void) { } +static inline void s5pc100_default_sdhci1(void) { } +static inline void s5pc100_default_sdhci2(void) { } + +#endif /* CONFIG_S5PC100_SETUP_SDHCI */ + +/* S5PV210 SDHCI setup */ + +#ifdef CONFIG_S5PV210_SETUP_SDHCI +static inline void s5pv210_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s5pv210_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s5pv210_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s5pv210_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s5pv210_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s5pv210_setup_sdhci2_cfg_gpio; +#endif +} + +static inline void s5pv210_default_sdhci3(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC3 + s3c_hsmmc3_def_platdata.cfg_gpio = s5pv210_setup_sdhci3_cfg_gpio; +#endif +} + +#else +static inline void s5pv210_default_sdhci0(void) { } +static inline void s5pv210_default_sdhci1(void) { } +static inline void s5pv210_default_sdhci2(void) { } +static inline void s5pv210_default_sdhci3(void) { } + +#endif /* CONFIG_S5PV210_SETUP_SDHCI */ + +static inline void s3c_sdhci_setname(int id, char *name) +{ + switch (id) { +#ifdef CONFIG_S3C_DEV_HSMMC + case 0: + s3c_device_hsmmc0.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC1 + case 1: + s3c_device_hsmmc1.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC2 + case 2: + s3c_device_hsmmc2.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC3 + case 3: + s3c_device_hsmmc3.name = name; + break; +#endif + default: + break; + } +} +#endif /* __PLAT_S3C_SDHCI_H */ diff --git a/arch/arm/plat-samsung/include/plat/spi-core.h b/arch/arm/plat-samsung/include/plat/spi-core.h new file mode 100644 index 00000000000..0b9428ab3fc --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/spi-core.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> + * + * 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 __PLAT_S3C_SPI_CORE_H +#define __PLAT_S3C_SPI_CORE_H + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c64xx_spi_setname(char *name) +{ +#ifdef CONFIG_S3C64XX_DEV_SPI0 + s3c64xx_device_spi0.name = name; +#endif +#ifdef CONFIG_S3C64XX_DEV_SPI1 + s3c64xx_device_spi1.name = name; +#endif +#ifdef CONFIG_S3C64XX_DEV_SPI2 + s3c64xx_device_spi2.name = name; +#endif +} + +#endif /* __PLAT_S3C_SPI_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/tv-core.h b/arch/arm/plat-samsung/include/plat/tv-core.h new file mode 100644 index 00000000000..3bc34f3ce28 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/tv-core.h @@ -0,0 +1,44 @@ +/* + * arch/arm/plat-samsung/include/plat/tv.h + * + * Copyright 2011 Samsung Electronics Co., Ltd. + * Tomasz Stanislawski <t.stanislaws@samsung.com> + * + * Samsung TV driver core functions + * + * 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 __SAMSUNG_PLAT_TV_H +#define __SAMSUNG_PLAT_TV_H __FILE__ + +/* + * These functions are only for use with the core support code, such as + * the CPU-specific initialization code. + */ + +/* Re-define device name to differentiate the subsystem in various SoCs. */ +static inline void s5p_hdmi_setname(char *name) +{ +#ifdef CONFIG_S5P_DEV_TV + s5p_device_hdmi.name = name; +#endif +} + +static inline void s5p_mixer_setname(char *name) +{ +#ifdef CONFIG_S5P_DEV_TV + s5p_device_mixer.name = name; +#endif +} + +static inline void s5p_sdo_setname(char *name) +{ +#ifdef CONFIG_S5P_DEV_TV + s5p_device_sdo.name = name; +#endif +} + +#endif /* __SAMSUNG_PLAT_TV_H */ diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h new file mode 100644 index 00000000000..ab34dfadb7f --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/usb-phy.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * 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 __PLAT_SAMSUNG_USB_PHY_H +#define __PLAT_SAMSUNG_USB_PHY_H __FILE__ + +#include <linux/usb/samsung_usb_phy.h> + +extern int s5p_usb_phy_init(struct platform_device *pdev, int type); +extern int s5p_usb_phy_exit(struct platform_device *pdev, int type); + +#endif /* __PLAT_SAMSUNG_USB_PHY_H */ diff --git a/arch/arm/plat-samsung/include/plat/wakeup-mask.h b/arch/arm/plat-samsung/include/plat/wakeup-mask.h new file mode 100644 index 00000000000..43e4acd2e1c --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/wakeup-mask.h @@ -0,0 +1,44 @@ +/* arch/arm/plat-samsung/include/plat/wakeup-mask.h + * + * Copyright 2010 Ben Dooks <ben-linux@fluff.org> + * + * Support for wakeup mask interrupts on newer SoCs + * + * 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 __PLAT_WAKEUP_MASK_H +#define __PLAT_WAKEUP_MASK_H __file__ + +/* if no irq yet defined, but still want to mask */ +#define NO_WAKEUP_IRQ (0x90000000) + +/** + * struct samsung_wakeup_mask - wakeup mask information + * @irq: The interrupt associated with this wakeup. + * @bit: The bit, as a (1 << bitno) controlling this source. + */ +struct samsung_wakeup_mask { + unsigned int irq; + u32 bit; +}; + +/** + * samsung_sync_wakemask - sync wakeup mask information for pm + * @reg: The register that is used. + * @masks: The list of masks to use. + * @nr_masks: The number of entries pointed to buy @masks. + * + * Synchronise the wakeup mask information at suspend time from the list + * of interrupts and control bits in @masks. We do this at suspend time + * as overriding the relevant irq chips is harder and the register is only + * required to be correct before we enter sleep. + */ +extern void samsung_sync_wakemask(void __iomem *reg, + struct samsung_wakeup_mask *masks, + int nr_masks); + +#endif /* __PLAT_WAKEUP_MASK_H */ diff --git a/arch/arm/plat-samsung/include/plat/watchdog-reset.h b/arch/arm/plat-samsung/include/plat/watchdog-reset.h new file mode 100644 index 00000000000..0386b8f7662 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/watchdog-reset.h @@ -0,0 +1,20 @@ +/* arch/arm/plat-s3c/include/plat/watchdog-reset.h + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - System define for arch_reset() function + * + * 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 __PLAT_SAMSUNG_WATCHDOG_RESET_H +#define __PLAT_SAMSUNG_WATCHDOG_RESET_H + +extern void samsung_wdt_reset(void); +extern void samsung_wdt_reset_of_init(void); +extern void samsung_wdt_reset_init(void __iomem *base); + +#endif /* __PLAT_SAMSUNG_WATCHDOG_RESET_H */ diff --git a/arch/arm/plat-samsung/init.c b/arch/arm/plat-samsung/init.c new file mode 100644 index 00000000000..a1f925f3121 --- /dev/null +++ b/arch/arm/plat-samsung/init.c @@ -0,0 +1,174 @@ +/* linux/arch/arm/plat-s3c/init.c + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C series CPU initialisation + * + * 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. +*/ + +/* + * NOTE: Code in this file is not used on S3C64xx when booting with + * Device Tree support. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/clock.h> + +static struct cpu_table *cpu; + +static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, + struct cpu_table *tab, + unsigned int count) +{ + for (; count != 0; count--, tab++) { + if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) + return tab; + } + + return NULL; +} + +void __init s3c_init_cpu(unsigned long idcode, + struct cpu_table *cputab, unsigned int cputab_size) +{ + cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); + + if (cpu == NULL) { + printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); + panic("Unknown S3C24XX CPU"); + } + + printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); + + if (cpu->init == NULL) { + printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); + panic("Unsupported Samsung CPU"); + } + + if (cpu->map_io) + cpu->map_io(); +} + +/* s3c24xx_init_clocks + * + * Initialise the clock subsystem and associated information from the + * given master crystal value. + * + * xtal = 0 -> use default PLL crystal value (normally 12MHz) + * != 0 -> PLL crystal value in Hz +*/ + +void __init s3c24xx_init_clocks(int xtal) +{ + if (xtal == 0) + xtal = 12*1000*1000; + + if (cpu == NULL) + panic("s3c24xx_init_clocks: no cpu setup?\n"); + + if (cpu->init_clocks == NULL) + panic("s3c24xx_init_clocks: cpu has no clock init\n"); + else + (cpu->init_clocks)(xtal); +} + +/* uart management */ +#if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) +static int nr_uarts __initdata = 0; + +#ifdef CONFIG_SERIAL_SAMSUNG_UARTS +static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]; +#endif + +/* s3c24xx_init_uartdevs + * + * copy the specified platform data and configuration into our central + * set of devices, before the data is thrown away after the init process. + * + * This also fills in the array passed to the serial driver for the + * early initialisation of the console. +*/ + +void __init s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no) +{ +#ifdef CONFIG_SERIAL_SAMSUNG_UARTS + struct platform_device *platdev; + struct s3c2410_uartcfg *cfgptr = uart_cfgs; + struct s3c24xx_uart_resources *resp; + int uart; + + memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); + + for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { + platdev = s3c24xx_uart_src[cfgptr->hwport]; + + resp = res + cfgptr->hwport; + + s3c24xx_uart_devs[uart] = platdev; + + platdev->name = name; + platdev->resource = resp->resources; + platdev->num_resources = resp->nr_resources; + + platdev->dev.platform_data = cfgptr; + } + + nr_uarts = no; +#endif +} + +void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + if (cpu == NULL) + return; + + if (cpu->init_uarts == NULL && IS_ENABLED(CONFIG_SAMSUNG_ATAGS)) { + printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); + } else + (cpu->init_uarts)(cfg, no); +} +#endif + +static int __init s3c_arch_init(void) +{ + int ret; + + // do the correct init for cpu + + if (cpu == NULL) { + /* Not needed when booting with device tree. */ + if (of_have_populated_dt()) + return 0; + panic("s3c_arch_init: NULL cpu\n"); + } + + ret = (cpu->init)(); + if (ret != 0) + return ret; +#if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) + ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); +#endif + return ret; +} + +arch_initcall(s3c_arch_init); diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c new file mode 100644 index 00000000000..b430e994628 --- /dev/null +++ b/arch/arm/plat-samsung/platformdata.c @@ -0,0 +1,60 @@ +/* linux/arch/arm/plat-samsung/platformdata.c + * + * Copyright 2010 Ben Dooks <ben-linux <at> fluff.org> + * + * Helper for platform data setting + * + * 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/slab.h> +#include <linux/string.h> +#include <linux/platform_device.h> + +#include <plat/devs.h> +#include <plat/sdhci.h> + +void __init *s3c_set_platdata(void *pd, size_t pdsize, + struct platform_device *pdev) +{ + void *npd; + + if (!pd) { + /* too early to use dev_name(), may not be registered */ + printk(KERN_ERR "%s: no platform data supplied\n", pdev->name); + return NULL; + } + + npd = kmemdup(pd, pdsize, GFP_KERNEL); + if (!npd) { + printk(KERN_ERR "%s: cannot clone platform data\n", pdev->name); + return NULL; + } + + pdev->dev.platform_data = npd; + return npd; +} + +void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, + struct s3c_sdhci_platdata *set) +{ + set->cd_type = pd->cd_type; + set->ext_cd_init = pd->ext_cd_init; + set->ext_cd_cleanup = pd->ext_cd_cleanup; + set->ext_cd_gpio = pd->ext_cd_gpio; + set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; + + if (pd->max_width) + set->max_width = pd->max_width; + if (pd->cfg_gpio) + set->cfg_gpio = pd->cfg_gpio; + if (pd->host_caps) + set->host_caps |= pd->host_caps; + if (pd->host_caps2) + set->host_caps2 |= pd->host_caps2; + if (pd->pm_caps) + set->pm_caps |= pd->pm_caps; +} diff --git a/arch/arm/plat-samsung/pm-check.c b/arch/arm/plat-samsung/pm-check.c new file mode 100644 index 00000000000..04aff2c31b4 --- /dev/null +++ b/arch/arm/plat-samsung/pm-check.c @@ -0,0 +1,237 @@ +/* linux/arch/arm/plat-s3c/pm-check.c + * originally in linux/arch/arm/plat-s3c24xx/pm.c + * + * Copyright (c) 2004-2008 Simtec Electronics + * http://armlinux.simtec.co.uk + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Power Mangament - suspend/resume memory corruptiuon check. + * + * 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/suspend.h> +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/ioport.h> +#include <linux/slab.h> + +#include <plat/pm-common.h> + +#if CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE < 1 +#error CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE must be a positive non-zero value +#endif + +/* suspend checking code... + * + * this next area does a set of crc checks over all the installed + * memory, so the system can verify if the resume was ok. + * + * CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, + * increasing it will mean that the area corrupted will be less easy to spot, + * and reducing the size will cause the CRC save area to grow +*/ + +#define CHECK_CHUNKSIZE (CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE * 1024) + +static u32 crc_size; /* size needed for the crc block */ +static u32 *crcs; /* allocated over suspend/resume */ + +typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); + +/* s3c_pm_run_res + * + * go through the given resource list, and look for system ram +*/ + +static void s3c_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) +{ + while (ptr != NULL) { + if (ptr->child != NULL) + s3c_pm_run_res(ptr->child, fn, arg); + + if ((ptr->flags & IORESOURCE_MEM) && + strcmp(ptr->name, "System RAM") == 0) { + S3C_PMDBG("Found system RAM at %08lx..%08lx\n", + (unsigned long)ptr->start, + (unsigned long)ptr->end); + arg = (fn)(ptr, arg); + } + + ptr = ptr->sibling; + } +} + +static void s3c_pm_run_sysram(run_fn_t fn, u32 *arg) +{ + s3c_pm_run_res(&iomem_resource, fn, arg); +} + +static u32 *s3c_pm_countram(struct resource *res, u32 *val) +{ + u32 size = (u32)resource_size(res); + + size += CHECK_CHUNKSIZE-1; + size /= CHECK_CHUNKSIZE; + + S3C_PMDBG("Area %08lx..%08lx, %d blocks\n", + (unsigned long)res->start, (unsigned long)res->end, size); + + *val += size * sizeof(u32); + return val; +} + +/* s3c_pm_prepare_check + * + * prepare the necessary information for creating the CRCs. This + * must be done before the final save, as it will require memory + * allocating, and thus touching bits of the kernel we do not + * know about. +*/ + +void s3c_pm_check_prepare(void) +{ + crc_size = 0; + + s3c_pm_run_sysram(s3c_pm_countram, &crc_size); + + S3C_PMDBG("s3c_pm_prepare_check: %u checks needed\n", crc_size); + + crcs = kmalloc(crc_size+4, GFP_KERNEL); + if (crcs == NULL) + printk(KERN_ERR "Cannot allocated CRC save area\n"); +} + +static u32 *s3c_pm_makecheck(struct resource *res, u32 *val) +{ + unsigned long addr, left; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + *val = crc32_le(~0, phys_to_virt(addr), left); + val++; + } + + return val; +} + +/* s3c_pm_check_store + * + * compute the CRC values for the memory blocks before the final + * sleep. +*/ + +void s3c_pm_check_store(void) +{ + if (crcs != NULL) + s3c_pm_run_sysram(s3c_pm_makecheck, crcs); +} + +/* in_region + * + * return TRUE if the area defined by ptr..ptr+size contains the + * what..what+whatsz +*/ + +static inline int in_region(void *ptr, int size, void *what, size_t whatsz) +{ + if ((what+whatsz) < ptr) + return 0; + + if (what > (ptr+size)) + return 0; + + return 1; +} + +/** + * s3c_pm_runcheck() - helper to check a resource on restore. + * @res: The resource to check + * @vak: Pointer to list of CRC32 values to check. + * + * Called from the s3c_pm_check_restore() via s3c_pm_run_sysram(), this + * function runs the given memory resource checking it against the stored + * CRC to ensure that memory is restored. The function tries to skip as + * many of the areas used during the suspend process. + */ +static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) +{ + unsigned long addr; + unsigned long left; + void *stkpage; + void *ptr; + u32 calc; + + stkpage = (void *)((u32)&calc & ~PAGE_MASK); + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + ptr = phys_to_virt(addr); + + if (in_region(ptr, left, stkpage, 4096)) { + S3C_PMDBG("skipping %08lx, has stack in\n", addr); + goto skip_check; + } + + if (in_region(ptr, left, crcs, crc_size)) { + S3C_PMDBG("skipping %08lx, has crc block in\n", addr); + goto skip_check; + } + + /* calculate and check the checksum */ + + calc = crc32_le(~0, ptr, left); + if (calc != *val) { + printk(KERN_ERR "Restore CRC error at " + "%08lx (%08x vs %08x)\n", addr, calc, *val); + + S3C_PMDBG("Restore CRC error at %08lx (%08x vs %08x)\n", + addr, calc, *val); + } + + skip_check: + val++; + } + + return val; +} + +/** + * s3c_pm_check_restore() - memory check called on resume + * + * check the CRCs after the restore event and free the memory used + * to hold them +*/ +void s3c_pm_check_restore(void) +{ + if (crcs != NULL) + s3c_pm_run_sysram(s3c_pm_runcheck, crcs); +} + +/** + * s3c_pm_check_cleanup() - free memory resources + * + * Free the resources that where allocated by the suspend + * memory check code. We do this separately from the + * s3c_pm_check_restore() function as we cannot call any + * functions that might sleep during that resume. + */ +void s3c_pm_check_cleanup(void) +{ + kfree(crcs); + crcs = NULL; +} + diff --git a/arch/arm/plat-samsung/pm-common.c b/arch/arm/plat-samsung/pm-common.c new file mode 100644 index 00000000000..515cd53372b --- /dev/null +++ b/arch/arm/plat-samsung/pm-common.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa <t.figa@samsung.com> + * Copyright (C) 2008 Openmoko, Inc. + * Copyright (C) 2004-2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Samsung common power management helper functions. + * + * 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/io.h> +#include <linux/kernel.h> + +#include <plat/pm-common.h> + +/* helper functions to save and restore register state */ + +/** + * s3c_pm_do_save() - save a set of registers for restoration on resume. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Run through the list of registers given, saving their contents in the + * array for later restoration when we wakeup. + */ +void s3c_pm_do_save(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + ptr->val = __raw_readl(ptr->reg); + S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val); + } +} + +/** + * s3c_pm_do_restore() - restore register values from the save list. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Restore the register values saved from s3c_pm_do_save(). + * + * Note, we do not use S3C_PMDBG() in here, as the system may not have + * restore the UARTs state yet +*/ + +void s3c_pm_do_restore(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + pr_debug("restore %p (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, __raw_readl(ptr->reg)); + + __raw_writel(ptr->val, ptr->reg); + } +} + +/** + * s3c_pm_do_restore_core() - early restore register values from save list. + * + * This is similar to s3c_pm_do_restore() except we try and minimise the + * side effects of the function in case registers that hardware might need + * to work has been restored. + * + * WARNING: Do not put any debug in here that may effect memory or use + * peripherals, as things may be changing! +*/ + +void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) + __raw_writel(ptr->val, ptr->reg); +} diff --git a/arch/arm/plat-samsung/pm-debug.c b/arch/arm/plat-samsung/pm-debug.c new file mode 100644 index 00000000000..8f19f66388d --- /dev/null +++ b/arch/arm/plat-samsung/pm-debug.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa <t.figa@samsung.com> + * Copyright (C) 2008 Openmoko, Inc. + * Copyright (C) 2004-2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Samsung common power management (suspend to RAM) debug support + * + * 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/serial_core.h> +#include <linux/io.h> + +#include <asm/mach/map.h> + +#include <plat/cpu.h> +#include <plat/pm-common.h> + +#ifdef CONFIG_SAMSUNG_ATAGS +#include <mach/pm-core.h> +#else +static inline void s3c_pm_debug_init_uart(void) {} +static inline void s3c_pm_arch_update_uart(void __iomem *regs, + struct pm_uart_save *save) {} +#endif + +static struct pm_uart_save uart_save; + +extern void printascii(const char *); + +void s3c_pm_dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsnprintf(buff, sizeof(buff), fmt, va); + va_end(va); + + printascii(buff); +} + +void s3c_pm_debug_init(void) +{ + /* restart uart clocks so we can use them to output */ + s3c_pm_debug_init_uart(); +} + +static inline void __iomem *s3c_pm_uart_base(void) +{ + unsigned long paddr; + unsigned long vaddr; + + debug_ll_addr(&paddr, &vaddr); + + return (void __iomem *)vaddr; +} + +void s3c_pm_save_uarts(void) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + save->ulcon = __raw_readl(regs + S3C2410_ULCON); + save->ucon = __raw_readl(regs + S3C2410_UCON); + save->ufcon = __raw_readl(regs + S3C2410_UFCON); + save->umcon = __raw_readl(regs + S3C2410_UMCON); + save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + if (!soc_is_s3c2410()) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + + S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); +} + +void s3c_pm_restore_uarts(void) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + s3c_pm_arch_update_uart(regs, save); + + __raw_writel(save->ulcon, regs + S3C2410_ULCON); + __raw_writel(save->ucon, regs + S3C2410_UCON); + __raw_writel(save->ufcon, regs + S3C2410_UFCON); + __raw_writel(save->umcon, regs + S3C2410_UMCON); + __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (!soc_is_s3c2410()) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); +} diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c new file mode 100644 index 00000000000..da268813901 --- /dev/null +++ b/arch/arm/plat-samsung/pm-gpio.c @@ -0,0 +1,388 @@ + +/* linux/arch/arm/plat-s3c/pm-gpio.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C series GPIO PM code + * + * 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/device.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) +#include <mach/gpio-samsung.h> +#endif + +#include <plat/gpio-core.h> +#include <plat/pm.h> + +/* PM GPIO helpers */ + +#define OFFS_CON (0x00) +#define OFFS_DAT (0x04) +#define OFFS_UP (0x08) + +static void samsung_gpio_pm_1bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); +} + +static void samsung_gpio_pm_1bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon; + + /* GPACON only has one bit per control / data and no PULLUPs. + * GPACON[x] = 0 => Output, 1 => SFN */ + + /* first set all SFN bits to SFN */ + + gpcon = old_gpcon | gps_gpcon; + __raw_writel(gpcon, base + OFFS_CON); + + /* now set all the other bits */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_1bit = { + .save = samsung_gpio_pm_1bit_save, + .resume = samsung_gpio_pm_1bit_resume, +}; + +static void samsung_gpio_pm_2bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP); +} + +/* Test whether the given masked+shifted bits of an GPIO configuration + * are one of the SFN (special function) modes. */ + +static inline int is_sfn(unsigned long con) +{ + return con >= 2; +} + +/* Test if the given masked+shifted GPIO configuration is an input */ + +static inline int is_in(unsigned long con) +{ + return con == 0; +} + +/* Test if the given masked+shifted GPIO configuration is an output */ + +static inline int is_out(unsigned long con) +{ + return con == 1; +} + +/** + * samsung_gpio_pm_2bit_resume() - restore the given GPIO bank + * @chip: The chip information to resume. + * + * Restore one of the GPIO banks that was saved during suspend. This is + * not as simple as once thought, due to the possibility of glitches + * from the order that the CON and DAT registers are set in. + * + * The three states the pin can be are {IN,OUT,SFN} which gives us 9 + * combinations of changes to check. Three of these, if the pin stays + * in the same configuration can be discounted. This leaves us with + * the following: + * + * { IN => OUT } Change DAT first + * { IN => SFN } Change CON first + * { OUT => SFN } Change CON first, so new data will not glitch + * { OUT => IN } Change CON first, so new data will not glitch + * { SFN => IN } Change CON first + * { SFN => OUT } Change DAT first, so new data will not glitch [1] + * + * We do not currently deal with the UP registers as these control + * weak resistors, so a small delay in change should not need to bring + * these into the calculations. + * + * [1] this assumes that writing to a pin DAT whilst in SFN will set the + * state for when it is next output. + */ +static void samsung_gpio_pm_2bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon, old, new, mask; + u32 change_mask = 0x0; + int nr; + + /* restore GPIO pull-up settings */ + __raw_writel(chip->pm_save[2], base + OFFS_UP); + + /* Create a change_mask of all the items that need to have + * their CON value changed before their DAT value, so that + * we minimise the work between the two settings. + */ + + for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + + /* Write the new CON settings */ + + gpcon = old_gpcon & ~change_mask; + gpcon |= gps_gpcon & change_mask; + + __raw_writel(gpcon, base + OFFS_CON); + + /* Now change any items that require DAT,CON */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_2bit = { + .save = samsung_gpio_pm_2bit_save, + .resume = samsung_gpio_pm_2bit_resume, +}; + +#if defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_PLAT_S5P) +static void samsung_gpio_pm_4bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP); + + if (chip->chip.ngpio > 8) + chip->pm_save[0] = __raw_readl(chip->base - 4); +} + +static u32 samsung_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) +{ + u32 old, new, mask; + u32 change_mask = 0x0; + int nr; + + for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + return change_mask; +} + +static void samsung_gpio_pm_4bit_con(struct samsung_gpio_chip *chip, int index) +{ + void __iomem *con = chip->base + (index * 4); + u32 old_gpcon = __raw_readl(con); + u32 gps_gpcon = chip->pm_save[index + 1]; + u32 gpcon, mask; + + mask = samsung_gpio_pm_4bit_mask(old_gpcon, gps_gpcon); + + gpcon = old_gpcon & ~mask; + gpcon |= gps_gpcon & mask; + + __raw_writel(gpcon, con); +} + +static void samsung_gpio_pm_4bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon[2]; + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpdat = chip->pm_save[2]; + + /* First, modify the CON settings */ + + old_gpcon[0] = 0; + old_gpcon[1] = __raw_readl(base + OFFS_CON); + + samsung_gpio_pm_4bit_con(chip, 0); + if (chip->chip.ngpio > 8) { + old_gpcon[0] = __raw_readl(base - 4); + samsung_gpio_pm_4bit_con(chip, -1); + } + + /* Now change the configurations that require DAT,CON */ + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[1], base + OFFS_CON); + if (chip->chip.ngpio > 8) + __raw_writel(chip->pm_save[0], base - 4); + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[3], base + OFFS_UP); + + if (chip->chip.ngpio > 8) { + S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[0], old_gpcon[1], + __raw_readl(base - 4), + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); + } else + S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[1], + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_4bit = { + .save = samsung_gpio_pm_4bit_save, + .resume = samsung_gpio_pm_4bit_resume, +}; +#endif /* CONFIG_ARCH_S3C64XX || CONFIG_PLAT_S5P */ + +/** + * samsung_pm_save_gpio() - save gpio chip data for suspend + * @ourchip: The chip for suspend. + */ +static void samsung_pm_save_gpio(struct samsung_gpio_chip *ourchip) +{ + struct samsung_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->save == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->save(ourchip); +} + +/** + * samsung_pm_save_gpios() - Save the state of the GPIO banks. + * + * For all the GPIO banks, save the state of each one ready for going + * into a suspend mode. + */ +void samsung_pm_save_gpios(void) +{ + struct samsung_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { + ourchip = samsung_gpiolib_getchip(gpio_nr); + if (!ourchip) { + gpio_nr++; + continue; + } + + samsung_pm_save_gpio(ourchip); + + S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n", + ourchip->chip.label, + ourchip->pm_save[0], + ourchip->pm_save[1], + ourchip->pm_save[2], + ourchip->pm_save[3]); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} + +/** + * samsung_pm_resume_gpio() - restore gpio chip data after suspend + * @ourchip: The suspended chip. + */ +static void samsung_pm_resume_gpio(struct samsung_gpio_chip *ourchip) +{ + struct samsung_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->resume == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->resume(ourchip); +} + +void samsung_pm_restore_gpios(void) +{ + struct samsung_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { + ourchip = samsung_gpiolib_getchip(gpio_nr); + if (!ourchip) { + gpio_nr++; + continue; + } + + samsung_pm_resume_gpio(ourchip); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c new file mode 100644 index 00000000000..f8c0f9797dc --- /dev/null +++ b/arch/arm/plat-samsung/pm.c @@ -0,0 +1,228 @@ +/* linux/arch/arm/plat-s3c/pm.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2004-2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C common power management (suspend to ram) support. + * + * 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/suspend.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/suspend.h> + +#ifdef CONFIG_SAMSUNG_ATAGS +#include <mach/map.h> +#ifndef CONFIG_ARCH_EXYNOS +#include <mach/regs-clock.h> +#include <mach/regs-irq.h> +#endif +#include <mach/irqs.h> +#endif + +#include <asm/irq.h> + +#include <plat/pm.h> +#include <mach/pm-core.h> + +/* for external use */ + +unsigned long s3c_pm_flags; + +/* The IRQ ext-int code goes here, it is too small to currently bother + * with its own file. */ + +unsigned long s3c_irqwake_intmask = 0xffffffffL; +unsigned long s3c_irqwake_eintmask = 0xffffffffL; + +int s3c_irqext_wake(struct irq_data *data, unsigned int state) +{ + unsigned long bit = 1L << IRQ_EINT_BIT(data->irq); + + if (!(s3c_irqwake_eintallow & bit)) + return -ENOENT; + + printk(KERN_INFO "wake %s for irq %d\n", + state ? "enabled" : "disabled", data->irq); + + if (!state) + s3c_irqwake_eintmask |= bit; + else + s3c_irqwake_eintmask &= ~bit; + + return 0; +} + +/* s3c2410_pm_show_resume_irqs + * + * print any IRQs asserted at resume time (ie, we woke from) +*/ +static void __maybe_unused s3c_pm_show_resume_irqs(int start, + unsigned long which, + unsigned long mask) +{ + int i; + + which &= ~mask; + + for (i = 0; i <= 31; i++) { + if (which & (1L<<i)) { + S3C_PMDBG("IRQ %d asserted at resume\n", start+i); + } + } +} + + +void (*pm_cpu_prep)(void); +int (*pm_cpu_sleep)(unsigned long); + +#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) + +/* s3c_pm_enter + * + * central control for sleep/resume process +*/ + +static int s3c_pm_enter(suspend_state_t state) +{ + int ret; + /* ensure the debug is initialised (if enabled) */ + + s3c_pm_debug_init(); + + S3C_PMDBG("%s(%d)\n", __func__, state); + + if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { + printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); + return -EINVAL; + } + + /* check if we have anything to wake-up with... bad things seem + * to happen if you suspend with no wakeup (system will often + * require a full power-cycle) + */ + + if (!of_have_populated_dt() && + !any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && + !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { + printk(KERN_ERR "%s: No wake-up sources!\n", __func__); + printk(KERN_ERR "%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + /* save all necessary core registers not covered by the drivers */ + + if (!of_have_populated_dt()) { + samsung_pm_save_gpios(); + samsung_pm_saved_gpios(); + } + + s3c_pm_save_uarts(); + s3c_pm_save_core(); + + /* set the irq configuration for wake */ + + s3c_pm_configure_extint(); + + S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", + s3c_irqwake_intmask, s3c_irqwake_eintmask); + + s3c_pm_arch_prepare_irqs(); + + /* call cpu specific preparation */ + + pm_cpu_prep(); + + /* flush cache back to ram */ + + flush_cache_all(); + + s3c_pm_check_store(); + + /* send the cpu to sleep... */ + + s3c_pm_arch_stop_clocks(); + + /* this will also act as our return point from when + * we resume as it saves its own register state and restores it + * during the resume. */ + + ret = cpu_suspend(0, pm_cpu_sleep); + if (ret) + return ret; + + /* restore the system state */ + + s3c_pm_restore_core(); + s3c_pm_restore_uarts(); + + if (!of_have_populated_dt()) { + samsung_pm_restore_gpios(); + s3c_pm_restored_gpios(); + } + + s3c_pm_debug_init(); + + /* check what irq (if any) restored the system */ + + s3c_pm_arch_show_resume_irqs(); + + S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); + + /* LEDs should now be 1110 */ + s3c_pm_debug_smdkled(1 << 1, 0); + + s3c_pm_check_restore(); + + /* ok, let's return from sleep */ + + S3C_PMDBG("S3C PM Resume (post-restore)\n"); + return 0; +} + +static int s3c_pm_prepare(void) +{ + /* prepare check area if configured */ + + s3c_pm_check_prepare(); + return 0; +} + +static void s3c_pm_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops s3c_pm_ops = { + .enter = s3c_pm_enter, + .prepare = s3c_pm_prepare, + .finish = s3c_pm_finish, + .valid = suspend_valid_only_mem, +}; + +/* s3c_pm_init + * + * Attach the power management functions. This should be called + * from the board specific initialisation if the board supports + * it. +*/ + +int __init s3c_pm_init(void) +{ + printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); + + suspend_set_ops(&s3c_pm_ops); + return 0; +} diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c new file mode 100644 index 00000000000..98b10ba67dc --- /dev/null +++ b/arch/arm/plat-samsung/s3c-dma-ops.c @@ -0,0 +1,146 @@ +/* linux/arch/arm/plat-samsung/s3c-dma-ops.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung S3C-DMA Operations + * + * 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/errno.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/export.h> + +#include <mach/dma.h> + +struct cb_data { + void (*fp) (void *); + void *fp_param; + unsigned ch; + struct list_head node; +}; + +static LIST_HEAD(dma_list); + +static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param, + int size, enum s3c2410_dma_buffresult res) +{ + struct cb_data *data = param; + + data->fp(data->fp_param); +} + +static unsigned s3c_dma_request(enum dma_ch dma_ch, + struct samsung_dma_req *param, + struct device *dev, char *ch_name) +{ + struct cb_data *data; + + if (s3c2410_dma_request(dma_ch, param->client, NULL) < 0) { + s3c2410_dma_free(dma_ch, param->client); + return 0; + } + + if (param->cap == DMA_CYCLIC) + s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR); + + data = kzalloc(sizeof(struct cb_data), GFP_KERNEL); + data->ch = dma_ch; + list_add_tail(&data->node, &dma_list); + + return (unsigned)dma_ch; +} + +static int s3c_dma_release(unsigned ch, void *param) +{ + struct cb_data *data; + + list_for_each_entry(data, &dma_list, node) + if (data->ch == ch) + break; + list_del(&data->node); + + s3c2410_dma_free(ch, param); + kfree(data); + + return 0; +} + +static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param) +{ + s3c2410_dma_devconfig(ch, param->direction, param->fifo); + s3c2410_dma_config(ch, param->width); + + return 0; +} + +static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param) +{ + struct cb_data *data; + dma_addr_t pos = param->buf; + dma_addr_t end = param->buf + param->len; + + list_for_each_entry(data, &dma_list, node) + if (data->ch == ch) + break; + + if (!data->fp) { + s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb); + data->fp = param->fp; + data->fp_param = param->fp_param; + } + + if (param->cap != DMA_CYCLIC) { + s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len); + return 0; + } + + while (pos < end) { + s3c2410_dma_enqueue(ch, (void *)data, pos, param->period); + pos += param->period; + } + + return 0; +} + +static inline int s3c_dma_trigger(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START); +} + +static inline int s3c_dma_started(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED); +} + +static inline int s3c_dma_flush(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH); +} + +static inline int s3c_dma_stop(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP); +} + +static struct samsung_dma_ops s3c_dma_ops = { + .request = s3c_dma_request, + .release = s3c_dma_release, + .config = s3c_dma_config, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .started = s3c_dma_started, + .flush = s3c_dma_flush, + .stop = s3c_dma_stop, +}; + +void *s3c_dma_get_ops(void) +{ + return &s3c_dma_ops; +} +EXPORT_SYMBOL(s3c_dma_get_ops); diff --git a/arch/arm/plat-samsung/s5p-clock.c b/arch/arm/plat-samsung/s5p-clock.c new file mode 100644 index 00000000000..48a15991103 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-clock.c @@ -0,0 +1,294 @@ +/* + * Copyright 2009 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P - Common clock support + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <asm/div64.h> + +#include <mach/regs-clock.h> + +#include <plat/clock.h> +#include <plat/clock-clksrc.h> +#include <plat/s5p-clock.h> + +/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call + * clk_ext_xtal_mux. +*/ +struct clk clk_ext_xtal_mux = { + .name = "ext_xtal", + .id = -1, +}; + +struct clk clk_xusbxti = { + .name = "xusbxti", + .id = -1, + .rate = 24000000, +}; + +struct clk s5p_clk_27m = { + .name = "clk_27m", + .id = -1, + .rate = 27000000, +}; + +/* 48MHz USB Phy clock output */ +struct clk clk_48m = { + .name = "clk_48m", + .id = -1, + .rate = 48000000, +}; + +/* APLL clock output + * No need .ctrlbit, this is always on +*/ +struct clk clk_fout_apll = { + .name = "fout_apll", + .id = -1, +}; + +/* BPLL clock output */ + +struct clk clk_fout_bpll = { + .name = "fout_bpll", + .id = -1, +}; + +struct clk clk_fout_bpll_div2 = { + .name = "fout_bpll_div2", + .id = -1, +}; + +/* CPLL clock output */ + +struct clk clk_fout_cpll = { + .name = "fout_cpll", + .id = -1, +}; + +/* MPLL clock output + * No need .ctrlbit, this is always on +*/ +struct clk clk_fout_mpll = { + .name = "fout_mpll", + .id = -1, +}; + +struct clk clk_fout_mpll_div2 = { + .name = "fout_mpll_div2", + .id = -1, +}; + +/* EPLL clock output */ +struct clk clk_fout_epll = { + .name = "fout_epll", + .id = -1, + .ctrlbit = (1 << 31), +}; + +/* DPLL clock output */ +struct clk clk_fout_dpll = { + .name = "fout_dpll", + .id = -1, + .ctrlbit = (1 << 31), +}; + +/* VPLL clock output */ +struct clk clk_fout_vpll = { + .name = "fout_vpll", + .id = -1, + .ctrlbit = (1 << 31), +}; + +/* Possible clock sources for APLL Mux */ +static struct clk *clk_src_apll_list[] = { + [0] = &clk_fin_apll, + [1] = &clk_fout_apll, +}; + +struct clksrc_sources clk_src_apll = { + .sources = clk_src_apll_list, + .nr_sources = ARRAY_SIZE(clk_src_apll_list), +}; + +/* Possible clock sources for BPLL Mux */ +static struct clk *clk_src_bpll_list[] = { + [0] = &clk_fin_bpll, + [1] = &clk_fout_bpll, +}; + +struct clksrc_sources clk_src_bpll = { + .sources = clk_src_bpll_list, + .nr_sources = ARRAY_SIZE(clk_src_bpll_list), +}; + +static struct clk *clk_src_bpll_fout_list[] = { + [0] = &clk_fout_bpll_div2, + [1] = &clk_fout_bpll, +}; + +struct clksrc_sources clk_src_bpll_fout = { + .sources = clk_src_bpll_fout_list, + .nr_sources = ARRAY_SIZE(clk_src_bpll_fout_list), +}; + +/* Possible clock sources for CPLL Mux */ +static struct clk *clk_src_cpll_list[] = { + [0] = &clk_fin_cpll, + [1] = &clk_fout_cpll, +}; + +struct clksrc_sources clk_src_cpll = { + .sources = clk_src_cpll_list, + .nr_sources = ARRAY_SIZE(clk_src_cpll_list), +}; + +/* Possible clock sources for MPLL Mux */ +static struct clk *clk_src_mpll_list[] = { + [0] = &clk_fin_mpll, + [1] = &clk_fout_mpll, +}; + +struct clksrc_sources clk_src_mpll = { + .sources = clk_src_mpll_list, + .nr_sources = ARRAY_SIZE(clk_src_mpll_list), +}; + +static struct clk *clk_src_mpll_fout_list[] = { + [0] = &clk_fout_mpll_div2, + [1] = &clk_fout_mpll, +}; + +struct clksrc_sources clk_src_mpll_fout = { + .sources = clk_src_mpll_fout_list, + .nr_sources = ARRAY_SIZE(clk_src_mpll_fout_list), +}; + +/* Possible clock sources for EPLL Mux */ +static struct clk *clk_src_epll_list[] = { + [0] = &clk_fin_epll, + [1] = &clk_fout_epll, +}; + +struct clksrc_sources clk_src_epll = { + .sources = clk_src_epll_list, + .nr_sources = ARRAY_SIZE(clk_src_epll_list), +}; + +/* Possible clock sources for DPLL Mux */ +static struct clk *clk_src_dpll_list[] = { + [0] = &clk_fin_dpll, + [1] = &clk_fout_dpll, +}; + +struct clksrc_sources clk_src_dpll = { + .sources = clk_src_dpll_list, + .nr_sources = ARRAY_SIZE(clk_src_dpll_list), +}; + +struct clk clk_vpll = { + .name = "vpll", + .id = -1, +}; + +int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable) +{ + unsigned int ctrlbit = clk->ctrlbit; + u32 con; + + con = __raw_readl(reg); + con = enable ? (con | ctrlbit) : (con & ~ctrlbit); + __raw_writel(con, reg); + return 0; +} + +int s5p_epll_enable(struct clk *clk, int enable) +{ + unsigned int ctrlbit = clk->ctrlbit; + unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit; + + if (enable) + __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON); + else + __raw_writel(epll_con, S5P_EPLL_CON); + + return 0; +} + +unsigned long s5p_epll_get_rate(struct clk *clk) +{ + return clk->rate; +} + +int s5p_spdif_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk *pclk; + int ret; + + pclk = clk_get_parent(clk); + if (IS_ERR(pclk)) + return -EINVAL; + + ret = pclk->ops->set_rate(pclk, rate); + clk_put(pclk); + + return ret; +} + +unsigned long s5p_spdif_get_rate(struct clk *clk) +{ + struct clk *pclk; + int rate; + + pclk = clk_get_parent(clk); + if (IS_ERR(pclk)) + return -EINVAL; + + rate = pclk->ops->get_rate(pclk); + clk_put(pclk); + + return rate; +} + +struct clk_ops s5p_sclk_spdif_ops = { + .set_rate = s5p_spdif_set_rate, + .get_rate = s5p_spdif_get_rate, +}; + +static struct clk *s5p_clks[] __initdata = { + &clk_ext_xtal_mux, + &clk_48m, + &s5p_clk_27m, + &clk_fout_apll, + &clk_fout_mpll, + &clk_fout_epll, + &clk_fout_dpll, + &clk_fout_vpll, + &clk_vpll, + &clk_xusbxti, +}; + +void __init s5p_register_clocks(unsigned long xtal_freq) +{ + int ret; + + clk_ext_xtal_mux.rate = xtal_freq; + + ret = s3c24xx_register_clocks(s5p_clks, ARRAY_SIZE(s5p_clks)); + if (ret > 0) + printk(KERN_ERR "Failed to register s5p clocks\n"); +} diff --git a/arch/arm/plat-samsung/s5p-dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c new file mode 100644 index 00000000000..469b86260fe --- /dev/null +++ b/arch/arm/plat-samsung/s5p-dev-mfc.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd + * + * Base S5P MFC resource and device definitions + * + * 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/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/memblock.h> +#include <linux/ioport.h> +#include <linux/of_fdt.h> +#include <linux/of.h> + +#include <plat/mfc.h> + +#ifdef CONFIG_SAMSUNG_ATAGS +#include <mach/map.h> +#include <mach/irqs.h> +#include <plat/devs.h> + +static struct resource s5p_mfc_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_MFC, SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_MFC), +}; + +struct platform_device s5p_device_mfc = { + .name = "s5p-mfc", + .id = -1, + .num_resources = ARRAY_SIZE(s5p_mfc_resource), + .resource = s5p_mfc_resource, +}; + +/* + * MFC hardware has 2 memory interfaces which are modelled as two separate + * platform devices to let dma-mapping distinguish between them. + * + * MFC parent device (s5p_device_mfc) must be registered before memory + * interface specific devices (s5p_device_mfc_l and s5p_device_mfc_r). + */ + +struct platform_device s5p_device_mfc_l = { + .name = "s5p-mfc-l", + .id = -1, + .dev = { + .parent = &s5p_device_mfc.dev, + .dma_mask = &s5p_device_mfc_l.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct platform_device s5p_device_mfc_r = { + .name = "s5p-mfc-r", + .id = -1, + .dev = { + .parent = &s5p_device_mfc.dev, + .dma_mask = &s5p_device_mfc_r.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#else +static struct platform_device s5p_device_mfc_l; +static struct platform_device s5p_device_mfc_r; +#endif + +struct s5p_mfc_reserved_mem { + phys_addr_t base; + unsigned long size; + struct device *dev; +}; + +static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata; + + +void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize, + phys_addr_t lbase, unsigned int lsize) +{ + int i; + + s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev; + s5p_mfc_mem[0].base = rbase; + s5p_mfc_mem[0].size = rsize; + + s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev; + s5p_mfc_mem[1].base = lbase; + s5p_mfc_mem[1].size = lsize; + + for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) { + struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i]; + if (memblock_remove(area->base, area->size)) { + printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n", + area->size, (unsigned long) area->base); + area->base = 0; + } + } +} + +#ifdef CONFIG_SAMSUNG_ATAGS +static int __init s5p_mfc_memory_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) { + struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i]; + if (!area->base) + continue; + + if (dma_declare_coherent_memory(area->dev, area->base, + area->base, area->size, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) + printk(KERN_ERR "Failed to declare coherent memory for MFC device (%ld bytes at 0x%08lx)\n", + area->size, (unsigned long) area->base); + } + return 0; +} +device_initcall(s5p_mfc_memory_init); +#endif + +#ifdef CONFIG_OF +int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + const __be32 *prop; + int len; + struct s5p_mfc_dt_meminfo mfc_mem; + + if (!data) + return 0; + + if (!of_flat_dt_is_compatible(node, data)) + return 0; + + prop = of_get_flat_dt_prop(node, "samsung,mfc-l", &len); + if (!prop || (len != 2 * sizeof(unsigned long))) + return 0; + + mfc_mem.loff = be32_to_cpu(prop[0]); + mfc_mem.lsize = be32_to_cpu(prop[1]); + + prop = of_get_flat_dt_prop(node, "samsung,mfc-r", &len); + if (!prop || (len != 2 * sizeof(unsigned long))) + return 0; + + mfc_mem.roff = be32_to_cpu(prop[0]); + mfc_mem.rsize = be32_to_cpu(prop[1]); + + s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize, + mfc_mem.loff, mfc_mem.lsize); + + return 1; +} +#endif diff --git a/arch/arm/plat-samsung/s5p-dev-uart.c b/arch/arm/plat-samsung/s5p-dev-uart.c new file mode 100644 index 00000000000..8c4487af98c --- /dev/null +++ b/arch/arm/plat-samsung/s5p-dev-uart.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009,2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Base S5P UART resource and device definitions + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <mach/map.h> + +#include <plat/devs.h> + + /* Serial port registrations */ + +static struct resource s5p_uart0_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_UART0, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART0), +}; + +static struct resource s5p_uart1_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_UART1, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART1), +}; + +static struct resource s5p_uart2_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_UART2, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART2), +}; + +static struct resource s5p_uart3_resource[] = { +#if CONFIG_SERIAL_SAMSUNG_UARTS > 3 + [0] = DEFINE_RES_MEM(S5P_PA_UART3, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART3), +#endif +}; + +static struct resource s5p_uart4_resource[] = { +#if CONFIG_SERIAL_SAMSUNG_UARTS > 4 + [0] = DEFINE_RES_MEM(S5P_PA_UART4, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART4), +#endif +}; + +static struct resource s5p_uart5_resource[] = { +#if CONFIG_SERIAL_SAMSUNG_UARTS > 5 + [0] = DEFINE_RES_MEM(S5P_PA_UART5, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART5), +#endif +}; + +struct s3c24xx_uart_resources s5p_uart_resources[] __initdata = { + [0] = { + .resources = s5p_uart0_resource, + .nr_resources = ARRAY_SIZE(s5p_uart0_resource), + }, + [1] = { + .resources = s5p_uart1_resource, + .nr_resources = ARRAY_SIZE(s5p_uart1_resource), + }, + [2] = { + .resources = s5p_uart2_resource, + .nr_resources = ARRAY_SIZE(s5p_uart2_resource), + }, + [3] = { + .resources = s5p_uart3_resource, + .nr_resources = ARRAY_SIZE(s5p_uart3_resource), + }, + [4] = { + .resources = s5p_uart4_resource, + .nr_resources = ARRAY_SIZE(s5p_uart4_resource), + }, + [5] = { + .resources = s5p_uart5_resource, + .nr_resources = ARRAY_SIZE(s5p_uart5_resource), + }, +}; diff --git a/arch/arm/plat-samsung/s5p-irq-eint.c b/arch/arm/plat-samsung/s5p-irq-eint.c new file mode 100644 index 00000000000..ebee4dc11a9 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-irq-eint.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5P - IRQ EINT support + * + * 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/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/irqchip/arm-vic.h> +#include <linux/of.h> + +#include <plat/regs-irqtype.h> + +#include <mach/map.h> +#include <plat/cpu.h> +#include <plat/pm.h> + +#include <plat/gpio-cfg.h> +#include <mach/regs-gpio.h> + +static inline void s5p_irq_eint_mask(struct irq_data *data) +{ + u32 mask; + + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq))); + mask |= eint_irq_to_bit(data->irq); + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq))); +} + +static void s5p_irq_eint_unmask(struct irq_data *data) +{ + u32 mask; + + mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq))); + mask &= ~(eint_irq_to_bit(data->irq)); + __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq))); +} + +static inline void s5p_irq_eint_ack(struct irq_data *data) +{ + __raw_writel(eint_irq_to_bit(data->irq), + S5P_EINT_PEND(EINT_REG_NR(data->irq))); +} + +static void s5p_irq_eint_maskack(struct irq_data *data) +{ + /* compiler should in-line these */ + s5p_irq_eint_mask(data); + s5p_irq_eint_ack(data); +} + +static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type) +{ + int offs = EINT_OFFSET(data->irq); + int shift; + u32 ctrl, mask; + u32 newvalue = 0; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + newvalue = S5P_IRQ_TYPE_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + newvalue = S5P_IRQ_TYPE_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_BOTH: + newvalue = S5P_IRQ_TYPE_EDGE_BOTH; + break; + + case IRQ_TYPE_LEVEL_LOW: + newvalue = S5P_IRQ_TYPE_LEVEL_LOW; + break; + + case IRQ_TYPE_LEVEL_HIGH: + newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -EINVAL; + } + + shift = (offs & 0x7) * 4; + mask = 0x7 << shift; + + ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq))); + ctrl &= ~mask; + ctrl |= newvalue << shift; + __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq))); + + if ((0 <= offs) && (offs < 8)) + s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE); + + else if ((8 <= offs) && (offs < 16)) + s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE); + + else if ((16 <= offs) && (offs < 24)) + s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE); + + else if ((24 <= offs) && (offs < 32)) + s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE); + + else + printk(KERN_ERR "No such irq number %d", offs); + + return 0; +} + +static struct irq_chip s5p_irq_eint = { + .name = "s5p-eint", + .irq_mask = s5p_irq_eint_mask, + .irq_unmask = s5p_irq_eint_unmask, + .irq_mask_ack = s5p_irq_eint_maskack, + .irq_ack = s5p_irq_eint_ack, + .irq_set_type = s5p_irq_eint_set_type, +#ifdef CONFIG_PM + .irq_set_wake = s3c_irqext_wake, +#endif +}; + +/* s5p_irq_demux_eint + * + * This function demuxes the IRQ from the group0 external interrupts, + * from EINTs 16 to 31. It is designed to be inlined into the specific + * handler s5p_irq_demux_eintX_Y. + * + * Each EINT pend/mask registers handle eight of them. + */ +static inline void s5p_irq_demux_eint(unsigned int start) +{ + u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start))); + u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start))); + unsigned int irq; + + status &= ~mask; + status &= 0xff; + + while (status) { + irq = fls(status) - 1; + generic_handle_irq(irq + start); + status &= ~(1 << irq); + } +} + +static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) +{ + s5p_irq_demux_eint(IRQ_EINT(16)); + s5p_irq_demux_eint(IRQ_EINT(24)); +} + +static inline void s5p_irq_vic_eint_mask(struct irq_data *data) +{ + void __iomem *base = irq_data_get_irq_chip_data(data); + + s5p_irq_eint_mask(data); + writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR); +} + +static void s5p_irq_vic_eint_unmask(struct irq_data *data) +{ + void __iomem *base = irq_data_get_irq_chip_data(data); + + s5p_irq_eint_unmask(data); + writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE); +} + +static inline void s5p_irq_vic_eint_ack(struct irq_data *data) +{ + __raw_writel(eint_irq_to_bit(data->irq), + S5P_EINT_PEND(EINT_REG_NR(data->irq))); +} + +static void s5p_irq_vic_eint_maskack(struct irq_data *data) +{ + s5p_irq_vic_eint_mask(data); + s5p_irq_vic_eint_ack(data); +} + +static struct irq_chip s5p_irq_vic_eint = { + .name = "s5p_vic_eint", + .irq_mask = s5p_irq_vic_eint_mask, + .irq_unmask = s5p_irq_vic_eint_unmask, + .irq_mask_ack = s5p_irq_vic_eint_maskack, + .irq_ack = s5p_irq_vic_eint_ack, + .irq_set_type = s5p_irq_eint_set_type, +#ifdef CONFIG_PM + .irq_set_wake = s3c_irqext_wake, +#endif +}; + +static int __init s5p_init_irq_eint(void) +{ + int irq; + + if (of_have_populated_dt()) + return -ENODEV; + + for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++) + irq_set_chip(irq, &s5p_irq_vic_eint); + + for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) { + irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + + irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31); + return 0; +} + +arch_initcall(s5p_init_irq_eint); diff --git a/arch/arm/plat-samsung/s5p-irq-gpioint.c b/arch/arm/plat-samsung/s5p-irq-gpioint.c new file mode 100644 index 00000000000..fafdb059043 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-irq-gpioint.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Author: Kyungmin Park <kyungmin.park@samsung.com> + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * Author: Marek Szyprowski <m.szyprowski@samsung.com> + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <mach/map.h> +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> + +#define GPIO_BASE(chip) ((void __iomem *)((unsigned long)((chip)->base) & 0xFFFFF000u)) + +#define CON_OFFSET 0x700 +#define MASK_OFFSET 0x900 +#define PEND_OFFSET 0xA00 +#define REG_OFFSET(x) ((x) << 2) + +struct s5p_gpioint_bank { + struct list_head list; + int start; + int nr_groups; + int irq; + struct samsung_gpio_chip **chips; + void (*handler)(unsigned int, struct irq_desc *); +}; + +static LIST_HEAD(banks); + +static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = gc->chip_types; + unsigned int shift = (d->irq - gc->irq_base) << 2; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + type = S5P_IRQ_TYPE_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + type = S5P_IRQ_TYPE_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + type = S5P_IRQ_TYPE_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + type = S5P_IRQ_TYPE_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + type = S5P_IRQ_TYPE_LEVEL_LOW; + break; + case IRQ_TYPE_NONE: + default: + printk(KERN_WARNING "No irq type\n"); + return -EINVAL; + } + + gc->type_cache &= ~(0x7 << shift); + gc->type_cache |= type << shift; + writel(gc->type_cache, gc->reg_base + ct->regs.type); + return 0; +} + +static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) +{ + struct s5p_gpioint_bank *bank = irq_get_handler_data(irq); + int group, pend_offset, mask_offset; + unsigned int pend, mask; + + struct irq_chip *chip = irq_get_chip(irq); + chained_irq_enter(chip, desc); + + for (group = 0; group < bank->nr_groups; group++) { + struct samsung_gpio_chip *chip = bank->chips[group]; + if (!chip) + continue; + + pend_offset = REG_OFFSET(group); + pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset); + if (!pend) + continue; + + mask_offset = REG_OFFSET(group); + mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset); + pend &= ~mask; + + while (pend) { + int offset = fls(pend) - 1; + int real_irq = chip->irq_base + offset; + generic_handle_irq(real_irq); + pend &= ~BIT(offset); + } + } + chained_irq_exit(chip, desc); +} + +static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip) +{ + static int used_gpioint_groups = 0; + int group = chip->group; + struct s5p_gpioint_bank *b, *bank = NULL; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) + return -ENOMEM; + + list_for_each_entry(b, &banks, list) { + if (group >= b->start && group < b->start + b->nr_groups) { + bank = b; + break; + } + } + if (!bank) + return -EINVAL; + + if (!bank->handler) { + bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) * + bank->nr_groups, GFP_KERNEL); + if (!bank->chips) + return -ENOMEM; + + irq_set_chained_handler(bank->irq, s5p_gpioint_handler); + irq_set_handler_data(bank->irq, bank); + bank->handler = s5p_gpioint_handler; + printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n", + bank->irq); + } + + /* + * chained GPIO irq has been successfully registered, allocate new gpio + * int group and assign irq nubmers + */ + chip->irq_base = S5P_GPIOINT_BASE + + used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; + used_gpioint_groups++; + + bank->chips[group - bank->start] = chip; + + gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base, + GPIO_BASE(chip), + handle_level_irq); + if (!gc) + return -ENOMEM; + ct = gc->chip_types; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_set_type = s5p_gpioint_set_type, + ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start); + ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start); + ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start); + irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio), + IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); + return 0; +} + +int __init s5p_register_gpio_interrupt(int pin) +{ + struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin); + int offset, group; + int ret; + + if (!my_chip) + return -EINVAL; + + offset = pin - my_chip->chip.base; + group = my_chip->group; + + /* check if the group has been already registered */ + if (my_chip->irq_base) + goto success; + + /* register gpio group */ + ret = s5p_gpioint_add(my_chip); + if (ret == 0) { + my_chip->chip.to_irq = samsung_gpiolib_to_irq; + printk(KERN_INFO "Registered interrupt support for gpio group %d.\n", + group); + goto success; + } + return ret; +success: + my_chip->bitmap_gpio_int |= BIT(offset); + + return my_chip->irq_base + offset; +} + +int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups) +{ + struct s5p_gpioint_bank *bank; + + bank = kzalloc(sizeof(*bank), GFP_KERNEL); + if (!bank) + return -ENOMEM; + + bank->start = start; + bank->nr_groups = nr_groups; + bank->irq = chain_irq; + + list_add_tail(&bank->list, &banks); + return 0; +} diff --git a/arch/arm/plat-samsung/s5p-irq-pm.c b/arch/arm/plat-samsung/s5p-irq-pm.c new file mode 100644 index 00000000000..52b16943617 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-irq-pm.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Based on arch/arm/plat-s3c24xx/irq-pm.c, + * Copyright (c) 2003,2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * 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/module.h> +#include <linux/interrupt.h> + +#include <plat/cpu.h> +#include <plat/irqs.h> +#include <plat/pm.h> +#include <mach/map.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-irq.h> + +/* state for IRQs over sleep */ + +/* default is to allow for EINT0..EINT31, and IRQ_RTC_TIC, IRQ_RTC_ALARM, + * as wakeup sources + * + * set bit to 1 in allow bitfield to enable the wakeup settings on it +*/ + +unsigned long s3c_irqwake_intallow = 0x00000006L; +unsigned long s3c_irqwake_eintallow = 0xffffffffL; + +int s3c_irq_wake(struct irq_data *data, unsigned int state) +{ + unsigned long irqbit; + unsigned int irq_rtc_tic, irq_rtc_alarm; + + irq_rtc_tic = IRQ_RTC_TIC; + irq_rtc_alarm = IRQ_RTC_ALARM; + + if (data->irq == irq_rtc_tic || data->irq == irq_rtc_alarm) { + irqbit = 1 << (data->irq + 1 - irq_rtc_alarm); + + if (!state) + s3c_irqwake_intmask |= irqbit; + else + s3c_irqwake_intmask &= ~irqbit; + } else { + return -ENOENT; + } + + return 0; +} + +static struct sleep_save eint_save[] = { + SAVE_ITEM(S5P_EINT_CON(0)), + SAVE_ITEM(S5P_EINT_CON(1)), + SAVE_ITEM(S5P_EINT_CON(2)), + SAVE_ITEM(S5P_EINT_CON(3)), + + SAVE_ITEM(S5P_EINT_FLTCON(0)), + SAVE_ITEM(S5P_EINT_FLTCON(1)), + SAVE_ITEM(S5P_EINT_FLTCON(2)), + SAVE_ITEM(S5P_EINT_FLTCON(3)), + SAVE_ITEM(S5P_EINT_FLTCON(4)), + SAVE_ITEM(S5P_EINT_FLTCON(5)), + SAVE_ITEM(S5P_EINT_FLTCON(6)), + SAVE_ITEM(S5P_EINT_FLTCON(7)), + + SAVE_ITEM(S5P_EINT_MASK(0)), + SAVE_ITEM(S5P_EINT_MASK(1)), + SAVE_ITEM(S5P_EINT_MASK(2)), + SAVE_ITEM(S5P_EINT_MASK(3)), +}; + +int s3c24xx_irq_suspend(void) +{ + s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); + + return 0; +} + +void s3c24xx_irq_resume(void) +{ + s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save)); +} + diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c new file mode 100644 index 00000000000..ddfaca9c79d --- /dev/null +++ b/arch/arm/plat-samsung/s5p-irq.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2009 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P - Interrupt handling + * + * 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/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/irqchip/arm-vic.h> + +#include <mach/irqs.h> +#include <mach/map.h> +#include <plat/cpu.h> + +void __init s5p_init_irq(u32 *vic, u32 num_vic) +{ +#ifdef CONFIG_ARM_VIC + int irq; + + /* initialize the VICs */ + for (irq = 0; irq < num_vic; irq++) + vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0); +#endif +} diff --git a/arch/arm/plat-samsung/s5p-pm.c b/arch/arm/plat-samsung/s5p-pm.c new file mode 100644 index 00000000000..0747468f093 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-pm.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5P Power Manager (Suspend-To-RAM) support + * + * Based on arch/arm/plat-s3c24xx/pm.c + * Copyright (c) 2004,2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * 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/suspend.h> +#include <plat/pm.h> + +#define PFX "s5p pm: " + +/* s3c_pm_configure_extint + * + * configure all external interrupt pins +*/ + +void s3c_pm_configure_extint(void) +{ + /* nothing here yet */ +} + +void s3c_pm_restore_core(void) +{ + /* nothing here yet */ +} + +void s3c_pm_save_core(void) +{ + /* nothing here yet */ +} + diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S new file mode 100644 index 00000000000..25c68ceb9e2 --- /dev/null +++ b/arch/arm/plat-samsung/s5p-sleep.S @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Common S5P Sleep Code + * Based on S3C64XX sleep code by: + * Ben Dooks, (c) 2008 Simtec Electronics + * + * 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 +*/ + +#include <linux/linkage.h> + + .data + .align + + /* + * sleep magic, to allow the bootloader to check for an valid + * image to resume to. Must be the first word before the + * s3c_cpu_resume entry. + */ + + .word 0x2bedf00d + + /* + * s3c_cpu_resume + * + * resume code entry for bootloader to call + */ + +ENTRY(s3c_cpu_resume) + b cpu_resume +ENDPROC(s3c_cpu_resume) diff --git a/arch/arm/plat-samsung/setup-camif.c b/arch/arm/plat-samsung/setup-camif.c new file mode 100644 index 00000000000..72d8edb8927 --- /dev/null +++ b/arch/arm/plat-samsung/setup-camif.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * + * Helper functions for S3C24XX/S3C64XX SoC series CAMIF driver + * + * 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/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio-samsung.h> + +/* Number of camera port pins, without FIELD */ +#define S3C_CAMIF_NUM_GPIOS 13 + +/* Default camera port configuration helpers. */ + +static void camif_get_gpios(int *gpio_start, int *gpio_reset) +{ +#ifdef CONFIG_ARCH_S3C24XX + *gpio_start = S3C2410_GPJ(0); + *gpio_reset = S3C2410_GPJ(12); +#else + /* s3c64xx */ + *gpio_start = S3C64XX_GPF(0); + *gpio_reset = S3C64XX_GPF(3); +#endif +} + +int s3c_camif_gpio_get(void) +{ + int gpio_start, gpio_reset; + int ret, i; + + camif_get_gpios(&gpio_start, &gpio_reset); + + for (i = 0; i < S3C_CAMIF_NUM_GPIOS; i++) { + int gpio = gpio_start + i; + + if (gpio == gpio_reset) + continue; + + ret = gpio_request(gpio, "camif"); + if (!ret) + ret = s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + if (ret) { + pr_err("failed to configure GPIO %d\n", gpio); + for (--i; i >= 0; i--) + gpio_free(gpio--); + return ret; + } + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + return 0; +} + +void s3c_camif_gpio_put(void) +{ + int i, gpio_start, gpio_reset; + + camif_get_gpios(&gpio_start, &gpio_reset); + + for (i = 0; i < S3C_CAMIF_NUM_GPIOS; i++) { + int gpio = gpio_start + i; + if (gpio != gpio_reset) + gpio_free(gpio); + } +} diff --git a/arch/arm/plat-samsung/wakeup-mask.c b/arch/arm/plat-samsung/wakeup-mask.c new file mode 100644 index 00000000000..20c3d9117cc --- /dev/null +++ b/arch/arm/plat-samsung/wakeup-mask.c @@ -0,0 +1,47 @@ +/* arch/arm/plat-samsung/wakeup-mask.c + * + * Copyright 2010 Ben Dooks <ben-linux@fluff.org> + * + * Support for wakeup mask interrupts on newer SoCs + * + * 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/spinlock.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <plat/wakeup-mask.h> +#include <plat/pm.h> + +void samsung_sync_wakemask(void __iomem *reg, + struct samsung_wakeup_mask *mask, int nr_mask) +{ + struct irq_data *data; + u32 val; + + val = __raw_readl(reg); + + for (; nr_mask > 0; nr_mask--, mask++) { + if (mask->irq == NO_WAKEUP_IRQ) { + val |= mask->bit; + continue; + } + + data = irq_get_irq_data(mask->irq); + + /* bit of a liberty to read this directly from irq_data. */ + if (irqd_is_wakeup_set(data)) + val &= ~mask->bit; + else + val |= mask->bit; + } + + printk(KERN_INFO "wakemask %08x => %08x\n", __raw_readl(reg), val); + __raw_writel(val, reg); +} diff --git a/arch/arm/plat-samsung/watchdog-reset.c b/arch/arm/plat-samsung/watchdog-reset.c new file mode 100644 index 00000000000..2ecb50bea04 --- /dev/null +++ b/arch/arm/plat-samsung/watchdog-reset.c @@ -0,0 +1,97 @@ +/* arch/arm/plat-samsung/watchdog-reset.c + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Coyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> + * + * Watchdog reset support for Samsung SoCs. + * + * 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/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#define S3C2410_WTCON 0x00 +#define S3C2410_WTDAT 0x04 +#define S3C2410_WTCNT 0x08 + +#define S3C2410_WTCON_ENABLE (1 << 5) +#define S3C2410_WTCON_DIV16 (0 << 3) +#define S3C2410_WTCON_RSTEN (1 << 0) +#define S3C2410_WTCON_PRESCALE(x) ((x) << 8) + +static void __iomem *wdt_base; +static struct clk *wdt_clock; + +void samsung_wdt_reset(void) +{ + if (!wdt_base) { + pr_err("%s: wdt reset not initialized\n", __func__); + /* delay to allow the serial port to show the message */ + mdelay(50); + return; + } + + if (!IS_ERR(wdt_clock)) + clk_prepare_enable(wdt_clock); + + /* disable watchdog, to be safe */ + __raw_writel(0, wdt_base + S3C2410_WTCON); + + /* put initial values into count and data */ + __raw_writel(0x80, wdt_base + S3C2410_WTCNT); + __raw_writel(0x80, wdt_base + S3C2410_WTDAT); + + /* set the watchdog to go and reset... */ + __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 | + S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20), + wdt_base + S3C2410_WTCON); + + /* wait for reset to assert... */ + mdelay(500); + + pr_err("Watchdog reset failed to assert reset\n"); + + /* delay to allow the serial port to show the message */ + mdelay(50); +} + +#ifdef CONFIG_OF +static const struct of_device_id s3c2410_wdt_match[] = { + { .compatible = "samsung,s3c2410-wdt" }, + {}, +}; + +void __init samsung_wdt_reset_of_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, s3c2410_wdt_match); + if (!np) { + pr_err("%s: failed to find watchdog node\n", __func__); + return; + } + + wdt_base = of_iomap(np, 0); + if (!wdt_base) { + pr_err("%s: failed to map watchdog registers\n", __func__); + return; + } + + wdt_clock = of_clk_get(np, 0); +} +#endif + +void __init samsung_wdt_reset_init(void __iomem *base) +{ + wdt_base = base; + wdt_clock = clk_get(NULL, "watchdog"); +} |
