From c197cec5fae7968a7154ee999f0a1b07938d1528 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 18 Jul 2009 10:12:25 +0100 Subject: ARM: S3C: Update hwmon device definition and name Change the hwmon device name to something more generic as this should be functional for both the s3c24xx and s3c64xx archs. Since it has yet to have a driver, it is pretty safe to change as there are no extant users. Also add the necessary entry in devs.h which seems to have been missed out at somepoint. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/devs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h index 2e170827e0b..1989ca1bb2b 100644 --- a/arch/arm/plat-s3c/include/plat/devs.h +++ b/arch/arm/plat-s3c/include/plat/devs.h @@ -46,6 +46,8 @@ extern struct platform_device s3c_device_hsmmc2; extern struct platform_device s3c_device_spi0; extern struct platform_device s3c_device_spi1; +extern struct platform_device s3c_device_hwmon; + extern struct platform_device s3c_device_nand; extern struct platform_device s3c_device_usbgadget; -- cgit v1.2.3 From e170adcb406504b8acd35554c69830c11916be1f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 18 Jul 2009 10:12:27 +0100 Subject: ARM: S3C: Add ADC synchronous read call. To add HWMON support, we need a synchronous read() call that blocks until completion. Add the client that is being service to the select and convert callbacks to make the code easier. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/adc.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h index d847bd476b6..5f3b1cd53b9 100644 --- a/arch/arm/plat-s3c/include/plat/adc.h +++ b/arch/arm/plat-s3c/include/plat/adc.h @@ -19,10 +19,14 @@ struct s3c_adc_client; 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)(unsigned selected), - void (*conv)(unsigned d0, unsigned d1, + 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); -- cgit v1.2.3 From bff78650a2b0ed42b8fb134b6a9b387e00027d67 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 18 Jul 2009 10:12:28 +0100 Subject: ARM: HWMON: S3C24XX series ADC driver Add support for the ADC controller on the S3C series of processors to drivers/hwmon for use with hardware monitoring systems. Signed-off-by: Ben Dooks Acked-by: Jean Delvare Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/hwmon.h | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 arch/arm/plat-s3c/include/plat/hwmon.h (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/hwmon.h b/arch/arm/plat-s3c/include/plat/hwmon.h new file mode 100644 index 00000000000..1ba88ea0aa3 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/hwmon.h @@ -0,0 +1,41 @@ +/* linux/arch/arm/plat-s3c/include/plat/hwmon.h + * + * Copyright 2005 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C - HWMon interface for ADC + * + * 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_ADC_HWMON_H +#define __ASM_ARCH_ADC_HWMON_H __FILE__ + +/** + * s3c_hwmon_chcfg - channel configuration + * @name: The name to give this channel. + * @mult: Multiply the ADC value read by this. + * @div: Divide the value from the ADC by this. + * + * The value read from the ADC is converted to a value that + * hwmon expects (mV) by result = (value_read * @mult) / @div. + */ +struct s3c_hwmon_chcfg { + const char *name; + unsigned int mult; + unsigned int div; +}; + +/** + * s3c_hwmon_pdata - HWMON platform data + * @in: One configuration for each possible channel used. + */ +struct s3c_hwmon_pdata { + struct s3c_hwmon_chcfg *in[8]; +}; + +#endif /* __ASM_ARCH_ADC_HWMON_H */ + -- cgit v1.2.3 From ea5fe9aedf512d20b75b7dcfd54ab99ae5c0934b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jul 2009 23:23:22 +0100 Subject: ARM: S3C: CPUFREQ: Documentation for cpufreq header Update arch/arm/plat-s3c/include/plat/cpu-freq.h to include kerneldoc style documentation. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/cpu-freq.h | 91 +++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 10 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/cpu-freq.h b/arch/arm/plat-s3c/include/plat/cpu-freq.h index c86a13307e9..0ba7670fd07 100644 --- a/arch/arm/plat-s3c/include/plat/cpu-freq.h +++ b/arch/arm/plat-s3c/include/plat/cpu-freq.h @@ -17,6 +17,21 @@ 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; @@ -25,33 +40,75 @@ struct s3c_freq { unsigned long pclk; }; -/* wrapper 'struct cpufreq_freqs' so that any drivers receiving the +/** + * 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; /* fclk / pclk */ - int h_divisor; /* fclk / hclk */ - int arm_divisor; /* not all cpus have this. */ - unsigned char dvs; /* using dvs mode to arm. */ + 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_config - current cpu frequency configuration + * @freq: The current settings for the core clocks. + * @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. + * + * 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_pllval pll; @@ -60,13 +117,27 @@ struct s3c_cpufreq_config { struct s3c_cpufreq_board *board; }; -/* s3c_cpufreq_board +/** + * 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. * - * per-board configuraton information, such as memory refresh and - * how to initialise IO timings. + * 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; /* refresh period in ns */ + unsigned int refresh; unsigned int auto_io:1; /* automatically init io timings. */ unsigned int need_io:1; /* set if needs io timing support. */ -- cgit v1.2.3 From d6fc87d3f7d236892e4d0003a07cd2b5171e5e27 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jul 2009 23:23:23 +0100 Subject: ARM: S3C: CPUFREQ: Move struct s3c_cpufreq_config to cpu-freq-core.h Move the structure s3c_cpufreq_config from cpu-freq.h to the less advertised cpu-freq-core.h as it is not needed by anything outside the core drivers. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/cpu-freq.h | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/cpu-freq.h b/arch/arm/plat-s3c/include/plat/cpu-freq.h index 0ba7670fd07..7b982b7f28c 100644 --- a/arch/arm/plat-s3c/include/plat/cpu-freq.h +++ b/arch/arm/plat-s3c/include/plat/cpu-freq.h @@ -97,26 +97,6 @@ struct s3c_pllval { unsigned long pll_reg; }; -/** - * struct s3c_cpufreq_config - current cpu frequency configuration - * @freq: The current settings for the core clocks. - * @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. - * - * 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_pllval pll; - struct s3c_clkdivs divs; - struct s3c_cpufreq_info *info; /* for core, not drivers */ - struct s3c_cpufreq_board *board; -}; - /** * struct s3c_cpufreq_board - per-board cpu frequency informatin * @refresh: The SDRAM refresh period in nanoseconds. -- cgit v1.2.3 From e13cf03eaae3792442c401860910d40f33c89a33 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jul 2009 23:23:35 +0100 Subject: ARM: S3C: Update CPU register mapping practices. Currently map-base.h defines the main virtual address mappings made for all the support S3C SoC series, but does not then define any base for per-cpu mappings to be made from. Add S3C_ADDR_CPU() macro to define an virtual address as an offset from the last of the core mappings. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/map-base.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/map-base.h b/arch/arm/plat-s3c/include/plat/map-base.h index b84289d32a5..250be311c85 100644 --- a/arch/arm/plat-s3c/include/plat/map-base.h +++ b/arch/arm/plat-s3c/include/plat/map-base.h @@ -32,9 +32,15 @@ #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) /* 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 */ -- cgit v1.2.3 From f0176794b6abc2e5239c07a58cf11b6f43d0f185 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jul 2009 23:23:38 +0100 Subject: ARM: S3C2410: Add S3C2410A sysdev. Add a sysdev S3C2410A sysdev to allow the differentiation of the S3C2410A from the S3C2410. This is needed for the CPUFREQ code to enable the extra features and update cpu specific information. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/cpu.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h index be541cbba07..fbc3d498e02 100644 --- a/arch/arm/plat-s3c/include/plat/cpu.h +++ b/arch/arm/plat-s3c/include/plat/cpu.h @@ -65,6 +65,7 @@ extern struct sys_timer s3c24xx_timer; /* system device classes */ extern struct sysdev_class s3c2410_sysclass; +extern struct sysdev_class s3c2410a_sysclass; extern struct sysdev_class s3c2412_sysclass; extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; -- cgit v1.2.3 From 14077ea63b5aea1db0142c1085d24aa0d11b9d36 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 1 Jul 2009 17:47:06 +0200 Subject: ARM: S3C: move s3c_device_nand from plat-s3c24xx to plat-s3c Move the s3c_device_nand platform device from plat-s3c24xx to plat-s3c, now that the nand driver also support the s3c64xx devices. Signed-off-by: Peter Korsgaard Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/Makefile | 1 + arch/arm/plat-s3c/dev-nand.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 arch/arm/plat-s3c/dev-nand.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index 0761766b183..d0b4a0fda5c 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += dev-audio.o obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o +obj-y += dev-nand.o diff --git a/arch/arm/plat-s3c/dev-nand.c b/arch/arm/plat-s3c/dev-nand.c new file mode 100644 index 00000000000..4e532373243 --- /dev/null +++ b/arch/arm/plat-s3c/dev-nand.c @@ -0,0 +1,30 @@ +/* + * S3C series device definition for nand device + * + * 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 +#include + +#include +#include + +static struct resource s3c_nand_resource[] = { + [0] = { + .start = S3C_PA_NAND, + .end = S3C_PA_NAND + SZ_1M, + .flags = IORESOURCE_MEM, + } +}; + +struct platform_device s3c_device_nand = { + .name = "s3c2410-nand", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_nand_resource), + .resource = s3c_nand_resource, +}; + +EXPORT_SYMBOL(s3c_device_nand); -- cgit v1.2.3 From b5ead1cda64336b589eb4353e00f69c818fb6603 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 1 Jul 2009 17:47:07 +0200 Subject: ARM: S3C: move timer/pwm handling from plat-s3c24xx to plat-s3c The s3c64xx devices use the same hardware core as s3c24xx, so move the timer/pwm handling to plat-s3c so it can be used by both. Signed-off-by: Peter Korsgaard Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/Makefile | 4 + arch/arm/plat-s3c/pwm.c | 406 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 arch/arm/plat-s3c/pwm.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index d0b4a0fda5c..3e27720ae35 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -28,6 +28,10 @@ obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM) += pm-gpio.o obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o +# PWM support + +obj-$(CONFIG_HAVE_PWM) += pwm.o + # devices obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o diff --git a/arch/arm/plat-s3c/pwm.c b/arch/arm/plat-s3c/pwm.c new file mode 100644 index 00000000000..f3d37ac5595 --- /dev/null +++ b/arch/arm/plat-s3c/pwm.c @@ -0,0 +1,406 @@ +/* arch/arm/plat-s3c/pwm.c + * + * Copyright (c) 2007 Ben Dooks + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks , + * + * S3C series PWM 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +struct pwm_device { + struct list_head list; + struct platform_device *pdev; + + struct clk *clk_div; + struct clk *clk; + const char *label; + + unsigned int period_ns; + unsigned int duty_ns; + + unsigned char tcon_base; + unsigned char running; + unsigned char use_count; + unsigned char pwm_id; +}; + +#define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg) + +static struct clk *clk_scaler[2]; + +/* Standard setup for a timer block. */ + +#define TIMER_RESOURCE_SIZE (1) + +#define TIMER_RESOURCE(_tmr, _irq) \ + (struct resource [TIMER_RESOURCE_SIZE]) { \ + [0] = { \ + .start = _irq, \ + .end = _irq, \ + .flags = IORESOURCE_IRQ \ + } \ + } + +#define DEFINE_S3C_TIMER(_tmr_no, _irq) \ + .name = "s3c24xx-pwm", \ + .id = _tmr_no, \ + .num_resources = TIMER_RESOURCE_SIZE, \ + .resource = TIMER_RESOURCE(_tmr_no, _irq), \ + +/* since we already have an static mapping for the timer, we do not + * bother setting any IO resource for the base. + */ + +struct platform_device s3c_device_timer[] = { + [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) }, + [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) }, + [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) }, + [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) }, + [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) }, +}; + +static inline int pwm_is_tdiv(struct pwm_device *pwm) +{ + return clk_get_parent(pwm->clk) == pwm->clk_div; +} + +static DEFINE_MUTEX(pwm_lock); +static LIST_HEAD(pwm_list); + +struct pwm_device *pwm_request(int pwm_id, const char *label) +{ + struct pwm_device *pwm; + int found = 0; + + mutex_lock(&pwm_lock); + + list_for_each_entry(pwm, &pwm_list, list) { + if (pwm->pwm_id == pwm_id) { + found = 1; + break; + } + } + + if (found) { + if (pwm->use_count == 0) { + pwm->use_count = 1; + pwm->label = label; + } else + pwm = ERR_PTR(-EBUSY); + } else + pwm = ERR_PTR(-ENOENT); + + mutex_unlock(&pwm_lock); + return pwm; +} + +EXPORT_SYMBOL(pwm_request); + + +void pwm_free(struct pwm_device *pwm) +{ + mutex_lock(&pwm_lock); + + if (pwm->use_count) { + pwm->use_count--; + pwm->label = NULL; + } else + printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id); + + mutex_unlock(&pwm_lock); +} + +EXPORT_SYMBOL(pwm_free); + +#define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0)) +#define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2)) +#define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3)) +#define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1)) + +int pwm_enable(struct pwm_device *pwm) +{ + unsigned long flags; + unsigned long tcon; + + local_irq_save(flags); + + tcon = __raw_readl(S3C2410_TCON); + tcon |= pwm_tcon_start(pwm); + __raw_writel(tcon, S3C2410_TCON); + + local_irq_restore(flags); + + pwm->running = 1; + return 0; +} + +EXPORT_SYMBOL(pwm_enable); + +void pwm_disable(struct pwm_device *pwm) +{ + unsigned long flags; + unsigned long tcon; + + local_irq_save(flags); + + tcon = __raw_readl(S3C2410_TCON); + tcon &= ~pwm_tcon_start(pwm); + __raw_writel(tcon, S3C2410_TCON); + + local_irq_restore(flags); + + pwm->running = 0; +} + +EXPORT_SYMBOL(pwm_disable); + +static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq) +{ + unsigned long tin_parent_rate; + unsigned int div; + + tin_parent_rate = clk_get_rate(clk_get_parent(pwm->clk_div)); + pwm_dbg(pwm, "tin parent at %lu\n", tin_parent_rate); + + for (div = 2; div <= 16; div *= 2) { + if ((tin_parent_rate / (div << 16)) < freq) + return tin_parent_rate / div; + } + + return tin_parent_rate / 16; +} + +#define NS_IN_HZ (1000000000UL) + +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +{ + unsigned long tin_rate; + unsigned long tin_ns; + unsigned long period; + unsigned long flags; + unsigned long tcon; + unsigned long tcnt; + long tcmp; + + /* We currently avoid using 64bit arithmetic by using the + * fact that anything faster than 1Hz is easily representable + * by 32bits. */ + + if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) + return -ERANGE; + + if (duty_ns > period_ns) + return -EINVAL; + + if (period_ns == pwm->period_ns && + duty_ns == pwm->duty_ns) + return 0; + + /* The TCMP and TCNT can be read without a lock, they're not + * shared between the timers. */ + + tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id)); + tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id)); + + period = NS_IN_HZ / period_ns; + + pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n", + duty_ns, period_ns, period); + + /* Check to see if we are changing the clock rate of the PWM */ + + if (pwm->period_ns != period_ns) { + if (pwm_is_tdiv(pwm)) { + tin_rate = pwm_calc_tin(pwm, period); + clk_set_rate(pwm->clk_div, tin_rate); + } else + tin_rate = clk_get_rate(pwm->clk); + + pwm->period_ns = period_ns; + + pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate); + + tin_ns = NS_IN_HZ / tin_rate; + tcnt = period_ns / tin_ns; + } else + tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk); + + /* Note, counters count down */ + + tcmp = duty_ns / tin_ns; + tcmp = tcnt - tcmp; + + pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); + + if (tcmp < 0) + tcmp = 0; + + /* Update the PWM register block. */ + + local_irq_save(flags); + + __raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id)); + __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id)); + + tcon = __raw_readl(S3C2410_TCON); + tcon |= pwm_tcon_manulupdate(pwm); + tcon |= pwm_tcon_autoreload(pwm); + __raw_writel(tcon, S3C2410_TCON); + + tcon &= ~pwm_tcon_manulupdate(pwm); + __raw_writel(tcon, S3C2410_TCON); + + local_irq_restore(flags); + + return 0; +} + +EXPORT_SYMBOL(pwm_config); + +static int pwm_register(struct pwm_device *pwm) +{ + pwm->duty_ns = -1; + pwm->period_ns = -1; + + mutex_lock(&pwm_lock); + list_add_tail(&pwm->list, &pwm_list); + mutex_unlock(&pwm_lock); + + return 0; +} + +static int s3c_pwm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pwm_device *pwm; + unsigned long flags; + unsigned long tcon; + unsigned int id = pdev->id; + int ret; + + if (id == 4) { + dev_err(dev, "TIMER4 is currently not supported\n"); + return -ENXIO; + } + + pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); + if (pwm == NULL) { + dev_err(dev, "failed to allocate pwm_device\n"); + return -ENOMEM; + } + + pwm->pdev = pdev; + pwm->pwm_id = id; + + /* calculate base of control bits in TCON */ + pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4; + + pwm->clk = clk_get(dev, "pwm-tin"); + if (IS_ERR(pwm->clk)) { + dev_err(dev, "failed to get pwm tin clk\n"); + ret = PTR_ERR(pwm->clk); + goto err_alloc; + } + + pwm->clk_div = clk_get(dev, "pwm-tdiv"); + if (IS_ERR(pwm->clk_div)) { + dev_err(dev, "failed to get pwm tdiv clk\n"); + ret = PTR_ERR(pwm->clk_div); + goto err_clk_tin; + } + + local_irq_save(flags); + + tcon = __raw_readl(S3C2410_TCON); + tcon |= pwm_tcon_invert(pwm); + __raw_writel(tcon, S3C2410_TCON); + + local_irq_restore(flags); + + + ret = pwm_register(pwm); + if (ret) { + dev_err(dev, "failed to register pwm\n"); + goto err_clk_tdiv; + } + + pwm_dbg(pwm, "config bits %02x\n", + (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f); + + dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", + clk_get_rate(pwm->clk), + clk_get_rate(pwm->clk_div), + pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base); + + platform_set_drvdata(pdev, pwm); + return 0; + + err_clk_tdiv: + clk_put(pwm->clk_div); + + err_clk_tin: + clk_put(pwm->clk); + + err_alloc: + kfree(pwm); + return ret; +} + +static int s3c_pwm_remove(struct platform_device *pdev) +{ + struct pwm_device *pwm = platform_get_drvdata(pdev); + + clk_put(pwm->clk_div); + clk_put(pwm->clk); + kfree(pwm); + + return 0; +} + +static struct platform_driver s3c_pwm_driver = { + .driver = { + .name = "s3c24xx-pwm", + .owner = THIS_MODULE, + }, + .probe = s3c_pwm_probe, + .remove = __devexit_p(s3c_pwm_remove), +}; + +static int __init pwm_init(void) +{ + int ret; + + clk_scaler[0] = clk_get(NULL, "pwm-scaler0"); + clk_scaler[1] = clk_get(NULL, "pwm-scaler1"); + + if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) { + printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__); + return -EINVAL; + } + + ret = platform_driver_register(&s3c_pwm_driver); + if (ret) + printk(KERN_ERR "%s: failed to add pwm driver\n", __func__); + + return ret; +} + +arch_initcall(pwm_init); -- cgit v1.2.3 From c233d94931cebc8ec805fb98856f34ad16d49e4f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Aug 2009 18:21:57 +0100 Subject: ARM: S3C: Move S3C64xx audio devices into S3C64xx directory Allowing us to make the Kconfig a little bit saner. Signed-off-by: Mark Brown Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/Makefile | 1 - arch/arm/plat-s3c/dev-audio.c | 68 ------------------------------------------- 2 files changed, 69 deletions(-) delete mode 100644 arch/arm/plat-s3c/dev-audio.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index 3e27720ae35..f32d045e7e3 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o obj-y += dev-i2c0.o obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o -obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += dev-audio.o obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o diff --git a/arch/arm/plat-s3c/dev-audio.c b/arch/arm/plat-s3c/dev-audio.c deleted file mode 100644 index 1322beb40dd..00000000000 --- a/arch/arm/plat-s3c/dev-audio.c +++ /dev/null @@ -1,68 +0,0 @@ -/* linux/arch/arm/plat-s3c/dev-audio.c - * - * Copyright 2009 Wolfson Microelectronics - * Mark Brown - * - - * 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 -#include -#include - -#include -#include - -#include - - -static struct resource s3c64xx_iis0_resource[] = { - [0] = { - .start = S3C64XX_PA_IIS0, - .end = S3C64XX_PA_IIS0 + 0x100 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device s3c64xx_device_iis0 = { - .name = "s3c64xx-iis", - .id = 0, - .num_resources = ARRAY_SIZE(s3c64xx_iis0_resource), - .resource = s3c64xx_iis0_resource, -}; -EXPORT_SYMBOL(s3c64xx_device_iis0); - -static struct resource s3c64xx_iis1_resource[] = { - [0] = { - .start = S3C64XX_PA_IIS1, - .end = S3C64XX_PA_IIS1 + 0x100 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device s3c64xx_device_iis1 = { - .name = "s3c64xx-iis", - .id = 1, - .num_resources = ARRAY_SIZE(s3c64xx_iis1_resource), - .resource = s3c64xx_iis1_resource, -}; -EXPORT_SYMBOL(s3c64xx_device_iis1); - -static struct resource s3c64xx_iisv4_resource[] = { - [0] = { - .start = S3C64XX_PA_IISV4, - .end = S3C64XX_PA_IISV4 + 0x100 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device s3c64xx_device_iisv4 = { - .name = "s3c64xx-iis-v4", - .id = -1, - .num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource), - .resource = s3c64xx_iisv4_resource, -}; -EXPORT_SYMBOL(s3c64xx_device_iisv4); -- cgit v1.2.3 From d91e9a7ab93e09e5a0fbed73f3a6a330f14620a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Aug 2009 18:29:57 +0100 Subject: ARM: S3C24XX: Add platform device for AC97 controller Move the definition of the "generic" IRQ in the process. Signed-off-by: Mark Brown Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/devs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h index 2e170827e0b..2e6599411c2 100644 --- a/arch/arm/plat-s3c/include/plat/devs.h +++ b/arch/arm/plat-s3c/include/plat/devs.h @@ -56,5 +56,6 @@ extern struct platform_device s3c_device_usb_hsotg; #ifdef CONFIG_CPU_S3C2440 extern struct platform_device s3c_device_camif; +extern struct platform_device s3c_device_ac97; #endif -- cgit v1.2.3 From db616eb67604242c11bfbb331bb143bfe4a2e386 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 16 Aug 2009 23:54:58 +0100 Subject: ARM: S3C: Add S3C_DEV_NAND Kconfig entry Currently the S5PC100 does not define S3C_PA_NAND, leaving the NAND device definitions in arch/arm/plat-s3c/dev-nand.c unbuildable. Add a KConfig entry to select whether this is built. As backwards compatibility, both the S3C24XX and S3C64XX define the new configuration in their main Kconfig files until better support for basing this selection on a per-machine basis can be sorted out. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/Kconfig | 5 +++++ arch/arm/plat-s3c/Makefile | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index 935c7558469..8931c5f0e46 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -198,4 +198,9 @@ config S3C_DEV_USB_HSOTG help Compile in platform device definition for USB high-speed OtG +config S3C_DEV_NAND + bool + help + Compile in platform device definition for NAND controller + endif diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index f32d045e7e3..3c09109e9e8 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -41,4 +41,4 @@ obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o -obj-y += dev-nand.o +obj-$(CONFIG_S3C_DEV_NAND) += dev-nand.o -- cgit v1.2.3