* [PATCH 00/15] Final Samsung PWM support cleanup
@ 2013-06-05 21:18 Tomasz Figa
2013-06-05 21:18 ` [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
` (15 more replies)
0 siblings, 16 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
Since we now have a proper Samsung PWM clocksource driver in place,
we can proceed with further cleanup of PWM timers support on Samsung SoCs.
This series attempts to achieve this goal by:
1) moving remaining Samsung platforms to the new clocksource driver
2) removing old clocksource driver
3) adding new multiplatform- and DT-aware PWM driver
4) moving all Samsung platforms to use the new PWM driver
5) removing old PWM driver
6) removing all PWM-related code that is not used anymore
Cleaning up the PWM driver is a bit tricky, because the design of current
driver makes it completely unsuitable for DT and multiplatform and would
require a heavy rework to make it usable, breaking any existing Samsung PWM
users by the way. To avoid any breakage I decided to keep the old driver,
add new one, move all platforms to it and then remove the old one.
See particular patches for more detailed descriptions.
On S3C6410-based Tiny6410 (Mini6410-compatible), after enabling pwm-beeper:
Tested-by: Tomasz Figa <tomasz.figa@gmail.com>
Needs testing on other platforms as I could only compile test for them.
Tomasz Figa (15):
ARM: SAMSUNG: Unify base address definitions of timer block
ARM: SAMSUNG: Add new PWM platform device
ARM: SAMSUNG: Set PWM platform data
ARM: SAMSUNG: Move all platforms to new clocksource driver
ARM: SAMSUNG: Remove old samsung-time driver
ARM: SAMSUNG: Remove unused PWM timer IRQ chip code
pwm: samsung: Rename to pwm-samsung-legacy
pwm: Add new pwm-samsung driver
ARM: SAMSUNG: Rework private data handling in dev-backlight
ARM: SAMSUNG: Modify board files to use new PWM platform device
pwm: Remove superseded pwm-samsung-legacy driver
ARM: SAMSUNG: Remove old PWM timer platform devices
ARM: SAMSUNG: Remove pwm-clock infrastructure
ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
ARM: SAMSUNG: Remove plat/regs-timer.h header
arch/arm/Kconfig | 1 -
arch/arm/mach-exynos/common.c | 3 +
arch/arm/mach-exynos/include/mach/irqs.h | 3 +-
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-nuri.c | 4 +-
arch/arm/mach-exynos/mach-origen.c | 3 +-
arch/arm/mach-exynos/mach-smdk4x12.c | 3 +-
arch/arm/mach-exynos/mach-smdkv310.c | 3 +-
arch/arm/mach-s3c24xx/Kconfig | 12 +-
arch/arm/mach-s3c24xx/clock-s3c2410.c | 1 -
arch/arm/mach-s3c24xx/clock-s3c2412.c | 1 -
arch/arm/mach-s3c24xx/clock-s3c2416.c | 2 -
arch/arm/mach-s3c24xx/clock-s3c2443.c | 2 -
arch/arm/mach-s3c24xx/common.c | 27 +
arch/arm/mach-s3c24xx/include/mach/map.h | 2 +
arch/arm/mach-s3c24xx/mach-h1940.c | 4 +-
arch/arm/mach-s3c24xx/mach-rx1950.c | 5 +-
arch/arm/mach-s3c64xx/Kconfig | 4 +-
arch/arm/mach-s3c64xx/clock.c | 2 -
arch/arm/mach-s3c64xx/common.c | 32 +-
arch/arm/mach-s3c64xx/include/mach/irqs.h | 8 -
arch/arm/mach-s3c64xx/include/mach/map.h | 1 +
arch/arm/mach-s3c64xx/irq-pm.c | 2 -
arch/arm/mach-s3c64xx/mach-crag6410.c | 4 +-
arch/arm/mach-s3c64xx/mach-hmt.c | 4 +-
arch/arm/mach-s3c64xx/mach-smartq.c | 4 +-
arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 +
arch/arm/mach-s5p64x0/Kconfig | 4 +-
arch/arm/mach-s5p64x0/clock-s5p6440.c | 2 -
arch/arm/mach-s5p64x0/clock-s5p6450.c | 2 -
arch/arm/mach-s5p64x0/common.c | 27 +
arch/arm/mach-s5p64x0/include/mach/irqs.h | 2 -
arch/arm/mach-s5p64x0/include/mach/map.h | 1 +
arch/arm/mach-s5p64x0/mach-smdk6440.c | 1 +
arch/arm/mach-s5p64x0/mach-smdk6450.c | 1 +
arch/arm/mach-s5p64x0/pm.c | 3 -
arch/arm/mach-s5pc100/Kconfig | 2 +-
arch/arm/mach-s5pc100/clock.c | 2 -
arch/arm/mach-s5pc100/common.c | 28 +
arch/arm/mach-s5pc100/include/mach/irqs.h | 2 -
arch/arm/mach-s5pc100/include/mach/map.h | 1 +
arch/arm/mach-s5pc100/mach-smdkc100.c | 1 +
arch/arm/mach-s5pv210/Kconfig | 2 +-
arch/arm/mach-s5pv210/clock.c | 1 -
arch/arm/mach-s5pv210/common.c | 28 +
arch/arm/mach-s5pv210/include/mach/irqs.h | 2 -
arch/arm/mach-s5pv210/include/mach/map.h | 1 +
arch/arm/mach-s5pv210/mach-smdkv210.c | 1 +
arch/arm/mach-s5pv210/pm.c | 10 -
arch/arm/plat-samsung/Kconfig | 14 -
arch/arm/plat-samsung/Makefile | 3 -
arch/arm/plat-samsung/dev-backlight.c | 61 ++-
arch/arm/plat-samsung/devs.c | 42 +-
arch/arm/plat-samsung/include/plat/clock.h | 4 -
arch/arm/plat-samsung/include/plat/devs.h | 1 +
arch/arm/plat-samsung/include/plat/irq-vic-timer.h | 13 -
arch/arm/plat-samsung/include/plat/irqs.h | 9 -
arch/arm/plat-samsung/include/plat/pwm-clock.h | 81 ---
arch/arm/plat-samsung/include/plat/pwm-core.h | 24 +
arch/arm/plat-samsung/include/plat/regs-timer.h | 124 -----
arch/arm/plat-samsung/include/plat/samsung-time.h | 23 -
arch/arm/plat-samsung/irq-vic-timer.c | 98 ----
arch/arm/plat-samsung/pwm-clock.c | 474 -----------------
arch/arm/plat-samsung/s5p-irq.c | 4 -
arch/arm/plat-samsung/samsung-time.c | 394 --------------
drivers/pwm/pwm-samsung.c | 575 ++++++++++++++-------
66 files changed, 627 insertions(+), 1580 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/irq-vic-timer.h
delete mode 100644 arch/arm/plat-samsung/include/plat/pwm-clock.h
create mode 100644 arch/arm/plat-samsung/include/plat/pwm-core.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-timer.h
delete mode 100644 arch/arm/plat-samsung/irq-vic-timer.c
delete mode 100644 arch/arm/plat-samsung/pwm-clock.c
delete mode 100644 arch/arm/plat-samsung/samsung-time.c
--
1.8.2.1
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 02/15] ARM: SAMSUNG: Add new PWM platform device Tomasz Figa
` (14 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <t.figa@samsung.com>
This patch makes all defintions of timer block base address use the same
prefix to allow using the common name to define platform device
resource.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-s3c24xx/include/mach/map.h | 2 ++
arch/arm/mach-s3c64xx/include/mach/map.h | 1 +
arch/arm/mach-s5p64x0/include/mach/map.h | 1 +
arch/arm/mach-s5pc100/include/mach/map.h | 1 +
arch/arm/mach-s5pv210/include/mach/map.h | 1 +
6 files changed, 7 insertions(+)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 92b29bb..5135dce 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -271,6 +271,7 @@
#define SAMSUNG_PA_ADC EXYNOS4_PA_ADC
#define SAMSUNG_PA_ADC1 EXYNOS4_PA_ADC1
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
+#define SAMSUNG_PA_TIMER EXYNOS4_PA_TIMER
/* Compatibility UART */
diff --git a/arch/arm/mach-s3c24xx/include/mach/map.h b/arch/arm/mach-s3c24xx/include/mach/map.h
index 8ba381f..444793f 100644
--- a/arch/arm/mach-s3c24xx/include/mach/map.h
+++ b/arch/arm/mach-s3c24xx/include/mach/map.h
@@ -167,4 +167,6 @@
#define S3C_PA_SPI0 S3C2443_PA_SPI0
#define S3C_PA_SPI1 S3C2443_PA_SPI1
+#define SAMSUNG_PA_TIMER S3C2410_PA_TIMER
+
#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/map.h b/arch/arm/mach-s3c64xx/include/mach/map.h
index 8e2097b..f55ccb1 100644
--- a/arch/arm/mach-s3c64xx/include/mach/map.h
+++ b/arch/arm/mach-s3c64xx/include/mach/map.h
@@ -121,5 +121,6 @@
#define SAMSUNG_PA_ADC S3C64XX_PA_ADC
#define SAMSUNG_PA_CFCON S3C64XX_PA_CFCON
#define SAMSUNG_PA_KEYPAD S3C64XX_PA_KEYPAD
+#define SAMSUNG_PA_TIMER S3C64XX_PA_TIMER
#endif /* __ASM_ARCH_6400_MAP_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/map.h b/arch/arm/mach-s5p64x0/include/mach/map.h
index 0c0175d..50a6e96 100644
--- a/arch/arm/mach-s5p64x0/include/mach/map.h
+++ b/arch/arm/mach-s5p64x0/include/mach/map.h
@@ -76,6 +76,7 @@
#define S5P_PA_TIMER S5P64X0_PA_TIMER
#define SAMSUNG_PA_ADC S5P64X0_PA_ADC
+#define SAMSUNG_PA_TIMER S5P64X0_PA_TIMER
/* UART */
diff --git a/arch/arm/mach-s5pc100/include/mach/map.h b/arch/arm/mach-s5pc100/include/mach/map.h
index 54bc4f8..2550b61 100644
--- a/arch/arm/mach-s5pc100/include/mach/map.h
+++ b/arch/arm/mach-s5pc100/include/mach/map.h
@@ -116,6 +116,7 @@
#define SAMSUNG_PA_ADC S5PC100_PA_TSADC
#define SAMSUNG_PA_CFCON S5PC100_PA_CFCON
#define SAMSUNG_PA_KEYPAD S5PC100_PA_KEYPAD
+#define SAMSUNG_PA_TIMER S5PC100_PA_TIMER
#define S5PC100_VA_OTHERS (S3C_VA_SYS + 0x10000)
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index b7c8a19..763929a 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -139,6 +139,7 @@
#define SAMSUNG_PA_ADC S5PV210_PA_ADC
#define SAMSUNG_PA_CFCON S5PV210_PA_CFCON
#define SAMSUNG_PA_KEYPAD S5PV210_PA_KEYPAD
+#define SAMSUNG_PA_TIMER S5PV210_PA_TIMER
/* UART */
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 02/15] ARM: SAMSUNG: Add new PWM platform device
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-05 21:18 ` [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 03/15] ARM: SAMSUNG: Set PWM platform data Tomasz Figa
` (13 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds new samsung_device_pwm platform device that represents
the whole PWM/timer block and includes memory and IRQ resources.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/plat-samsung/devs.c | 17 +++++++++++++++++
arch/arm/plat-samsung/include/plat/devs.h | 1 +
arch/arm/plat-samsung/include/plat/pwm-core.h | 24 ++++++++++++++++++++++++
3 files changed, 42 insertions(+)
create mode 100644 arch/arm/plat-samsung/include/plat/pwm-core.h
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 0f9c3f4..bba6d78 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -58,6 +58,7 @@
#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>
@@ -1127,6 +1128,22 @@ struct platform_device s3c_device_timer[] = {
[3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
[4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
};
+
+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 */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 87d501f..0dc4ac4 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -134,6 +134,7 @@ 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 */
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 0000000..df50f5c
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/pwm-core.h
@@ -0,0 +1,24 @@
+/*
+ * linux/arch/arm/plat-samsung/onenand-core.h
+ *
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Samsung PWM 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_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 */
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 03/15] ARM: SAMSUNG: Set PWM platform data
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-05 21:18 ` [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
2013-06-05 21:18 ` [PATCH 02/15] ARM: SAMSUNG: Add new PWM platform device Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 04/15] ARM: SAMSUNG: Move all platforms to new clocksource driver Tomasz Figa
` (12 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <t.figa@samsung.com>
This patch adds PWM platform data needed for legacy (non-DT) platforms
to handle SoC-specific bits of the PWM/timer block.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
arch/arm/mach-exynos/common.c | 3 +++
arch/arm/mach-s3c24xx/common.c | 11 +++++++++++
arch/arm/mach-s3c64xx/common.c | 11 +++++++++++
arch/arm/mach-s5p64x0/common.c | 10 ++++++++++
arch/arm/mach-s5pc100/common.c | 11 +++++++++++
arch/arm/mach-s5pv210/common.c | 11 +++++++++++
6 files changed, 57 insertions(+)
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 027c9e7..6b368a8 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -52,6 +52,7 @@
#include <plat/fb-core.h>
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
+#include <plat/pwm-core.h>
#include <plat/tv-core.h>
#include <plat/spi-core.h>
#include <plat/regs-serial.h>
@@ -443,6 +444,8 @@ static void __init exynos4_map_io(void)
s5p_hdmi_setname("exynos4-hdmi");
s3c64xx_spi_setname("exynos4210-spi");
+
+ samsung_pwm_set_platdata(&exynos4_pwm_variant);
}
static void __init exynos5_map_io(void)
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index c157103..e5e7d7d 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
+#include <clocksource/samsung_pwm.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -49,6 +50,7 @@
#include <plat/clock.h>
#include <plat/cpu-freq.h>
#include <plat/pll.h>
+#include <plat/pwm-core.h>
#include "common.h"
@@ -216,6 +218,13 @@ static void s3c24xx_default_idle(void)
S3C2410_CLKCON);
}
+static struct samsung_pwm_variant s3c24xx_pwm_variant = {
+ .bits = 16,
+ .div_base = 1,
+ .has_tint_cstat = false,
+ .tclk_mask = (1 << 4),
+};
+
void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
{
arm_pm_idle = s3c24xx_default_idle;
@@ -232,6 +241,8 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
s3c24xx_init_cpu();
s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
+
+ samsung_pwm_set_platdata(&s3c24xx_pwm_variant);
}
/* Serial port registrations */
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 0b9c0ba..5f3530e 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -26,6 +26,7 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/irqchip/arm-vic.h>
+#include <clocksource/samsung_pwm.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -42,6 +43,7 @@
#include <plat/gpio-cfg.h>
#include <plat/irq-uart.h>
#include <plat/irq-vic-timer.h>
+#include <plat/pwm-core.h>
#include <plat/regs-irqtype.h>
#include <plat/regs-serial.h>
#include <plat/watchdog-reset.h>
@@ -148,6 +150,13 @@ static struct device s3c64xx_dev = {
.bus = &s3c64xx_subsys,
};
+static struct samsung_pwm_variant s3c64xx_pwm_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
+};
+
/* read cpu identification code */
void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
@@ -160,6 +169,8 @@ void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
s3c64xx_init_cpu();
s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
+
+ samsung_pwm_set_platdata(&s3c64xx_pwm_variant);
}
static __init int s3c64xx_dev_init(void)
diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c
index 8ae5800..50edd3c 100644
--- a/arch/arm/mach-s5p64x0/common.c
+++ b/arch/arm/mach-s5p64x0/common.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/device.h>
#include <linux/serial_core.h>
+#include <clocksource/samsung_pwm.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
@@ -46,6 +47,7 @@
#include <plat/fb-core.h>
#include <plat/spi-core.h>
#include <plat/gpio-cfg.h>
+#include <plat/pwm-core.h>
#include <plat/regs-irqtype.h>
#include <plat/regs-serial.h>
#include <plat/watchdog-reset.h>
@@ -156,6 +158,13 @@ static void s5p64x0_idle(void)
cpu_do_idle();
}
+static struct samsung_pwm_variant s5p64x0_pwm_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = 0,
+};
+
/*
* s5p64x0_map_io
*
@@ -173,6 +182,7 @@ void __init s5p64x0_init_io(struct map_desc *mach_desc, int size)
s5p_init_cpu(S5P64X0_SYS_ID);
s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
+ samsung_pwm_set_platdata(&s5p64x0_pwm_variant);
}
void __init s5p6440_map_io(void)
diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c
index cc6e561..e56a4d8 100644
--- a/arch/arm/mach-s5pc100/common.c
+++ b/arch/arm/mach-s5pc100/common.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/device.h>
#include <linux/serial_core.h>
+#include <clocksource/samsung_pwm.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
@@ -45,6 +46,7 @@
#include <plat/fb-core.h>
#include <plat/iic-core.h>
#include <plat/onenand-core.h>
+#include <plat/pwm-core.h>
#include <plat/spi-core.h>
#include <plat/regs-serial.h>
#include <plat/watchdog-reset.h>
@@ -131,6 +133,13 @@ static struct map_desc s5pc100_iodesc[] __initdata = {
}
};
+static struct samsung_pwm_variant s5pc100_pwm_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = (1 << 5),
+};
+
/*
* s5pc100_map_io
*
@@ -148,6 +157,8 @@ void __init s5pc100_init_io(struct map_desc *mach_desc, int size)
s5p_init_cpu(S5P_VA_CHIPID);
s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
+
+ samsung_pwm_set_platdata(&s5pc100_pwm_variant);
}
void __init s5pc100_map_io(void)
diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
index 9dfe93e..4eba33d 100644
--- a/arch/arm/mach-s5pv210/common.c
+++ b/arch/arm/mach-s5pv210/common.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/device.h>
+#include <clocksource/samsung_pwm.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
@@ -42,6 +43,7 @@
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
#include <plat/keypad-core.h>
+#include <plat/pwm-core.h>
#include <plat/tv-core.h>
#include <plat/spi-core.h>
#include <plat/regs-serial.h>
@@ -148,6 +150,13 @@ void s5pv210_restart(char mode, const char *cmd)
__raw_writel(0x1, S5P_SWRESET);
}
+static struct samsung_pwm_variant s5pv210_pwm_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = (1 << 5),
+};
+
/*
* s5pv210_map_io
*
@@ -165,6 +174,8 @@ void __init s5pv210_init_io(struct map_desc *mach_desc, int size)
s5p_init_cpu(S5P_VA_CHIPID);
s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
+
+ samsung_pwm_set_platdata(&s5pv210_pwm_variant);
}
void __init s5pv210_map_io(void)
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 04/15] ARM: SAMSUNG: Move all platforms to new clocksource driver
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (2 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 03/15] ARM: SAMSUNG: Set PWM platform data Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 05/15] ARM: SAMSUNG: Remove old samsung-time driver Tomasz Figa
` (11 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch moves all Samsung platforms using PWM clocksource from legacy
samsung-time to new samsung-pwm-timer driver.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/mach-s3c24xx/Kconfig | 12 ++++++------
arch/arm/mach-s3c24xx/common.c | 16 ++++++++++++++++
arch/arm/mach-s3c64xx/Kconfig | 4 ++--
arch/arm/mach-s3c64xx/common.c | 17 +++++++++++++++++
arch/arm/mach-s5p64x0/Kconfig | 4 ++--
arch/arm/mach-s5p64x0/common.c | 17 +++++++++++++++++
arch/arm/mach-s5pc100/Kconfig | 2 +-
arch/arm/mach-s5pc100/common.c | 17 +++++++++++++++++
arch/arm/mach-s5pv210/Kconfig | 2 +-
arch/arm/mach-s5pv210/common.c | 17 +++++++++++++++++
10 files changed, 96 insertions(+), 12 deletions(-)
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
index 7ef7119..97a9b90 100644
--- a/arch/arm/mach-s3c24xx/Kconfig
+++ b/arch/arm/mach-s3c24xx/Kconfig
@@ -30,7 +30,7 @@ config CPU_S3C2410
select S3C2410_CLOCK
select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ
select S3C2410_PM if PM
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
@@ -41,7 +41,7 @@ config CPU_S3C2412
select CPU_LLSERIAL_S3C2440
select S3C2412_DMA if S3C24XX_DMA
select S3C2412_PM if PM
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
@@ -53,7 +53,7 @@ config CPU_S3C2416
select S3C2443_COMMON
select S3C2443_DMA if S3C24XX_DMA
select SAMSUNG_CLKSRC
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for the S3C2416 SoC from the S3C24XX line
@@ -64,7 +64,7 @@ config CPU_S3C2440
select S3C2410_CLOCK
select S3C2410_PM if PM
select S3C2440_DMA if S3C24XX_DMA
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for S3C2440 Samsung Mobile CPU based systems.
@@ -74,7 +74,7 @@ config CPU_S3C2442
select CPU_LLSERIAL_S3C2440
select S3C2410_CLOCK
select S3C2410_PM if PM
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for S3C2442 Samsung Mobile CPU based systems.
@@ -89,7 +89,7 @@ config CPU_S3C2443
select S3C2443_COMMON
select S3C2443_DMA if S3C24XX_DMA
select SAMSUNG_CLKSRC
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Support for the S3C2443 SoC from the S3C24XX line
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index e5e7d7d..457261c 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -245,6 +245,22 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
samsung_pwm_set_platdata(&s3c24xx_pwm_variant);
}
+void __init samsung_set_timer_source(unsigned int event, unsigned int source)
+{
+ s3c24xx_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1;
+ s3c24xx_pwm_variant.output_mask &= ~(BIT(event) | BIT(source));
+}
+
+void __init samsung_timer_init(void)
+{
+ unsigned int timer_irqs[SAMSUNG_PWM_NUM] = {
+ IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2, IRQ_TIMER3, IRQ_TIMER4,
+ };
+
+ samsung_pwm_clocksource_init(S3C_VA_TIMER,
+ timer_irqs, &s3c24xx_pwm_variant);
+}
+
/* Serial port registrations */
#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 2057853..f78a6a0 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -17,13 +17,13 @@ config PLAT_S3C64XX
# Configuration options for the S3C6410 CPU
config CPU_S3C6400
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
bool
help
Enable S3C6400 CPU support
config CPU_S3C6410
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
bool
help
Enable S3C6410 CPU support
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 5f3530e..add8451 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -157,6 +157,23 @@ static struct samsung_pwm_variant s3c64xx_pwm_variant = {
.tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
};
+void __init samsung_set_timer_source(unsigned int event, unsigned int source)
+{
+ s3c64xx_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1;
+ s3c64xx_pwm_variant.output_mask &= ~(BIT(event) | BIT(source));
+}
+
+void __init samsung_timer_init(void)
+{
+ unsigned int timer_irqs[SAMSUNG_PWM_NUM] = {
+ IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
+ IRQ_TIMER3_VIC, IRQ_TIMER4_VIC,
+ };
+
+ samsung_pwm_clocksource_init(S3C_VA_TIMER,
+ timer_irqs, &s3c64xx_pwm_variant);
+}
+
/* read cpu identification code */
void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 5a707bd..a39cd9e 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -11,14 +11,14 @@ config CPU_S5P6440
bool
select S5P_SLEEP if PM
select SAMSUNG_DMADEV
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
select SAMSUNG_WAKEMASK if PM
help
Enable S5P6440 CPU support
config CPU_S5P6450
bool
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
select S5P_SLEEP if PM
select SAMSUNG_DMADEV
select SAMSUNG_WAKEMASK if PM
diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c
index 50edd3c..5b1ce58 100644
--- a/arch/arm/mach-s5p64x0/common.c
+++ b/arch/arm/mach-s5p64x0/common.c
@@ -165,6 +165,23 @@ static struct samsung_pwm_variant s5p64x0_pwm_variant = {
.tclk_mask = 0,
};
+void __init samsung_set_timer_source(unsigned int event, unsigned int source)
+{
+ s5p64x0_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1;
+ s5p64x0_pwm_variant.output_mask &= ~(BIT(event) | BIT(source));
+}
+
+void __init samsung_timer_init(void)
+{
+ unsigned int timer_irqs[SAMSUNG_PWM_NUM] = {
+ IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
+ IRQ_TIMER3_VIC, IRQ_TIMER4_VIC,
+ };
+
+ samsung_pwm_clocksource_init(S3C_VA_TIMER,
+ timer_irqs, &s5p64x0_pwm_variant);
+}
+
/*
* s5p64x0_map_io
*
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index 2f456a4..2094a9b 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -11,7 +11,7 @@ config CPU_S5PC100
bool
select S5P_EXT_INT
select SAMSUNG_DMADEV
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Enable S5PC100 CPU support
diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c
index e56a4d8..1db8356 100644
--- a/arch/arm/mach-s5pc100/common.c
+++ b/arch/arm/mach-s5pc100/common.c
@@ -140,6 +140,23 @@ static struct samsung_pwm_variant s5pc100_pwm_variant = {
.tclk_mask = (1 << 5),
};
+void __init samsung_set_timer_source(unsigned int event, unsigned int source)
+{
+ s5pc100_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1;
+ s5pc100_pwm_variant.output_mask &= ~(BIT(event) | BIT(source));
+}
+
+void __init samsung_timer_init(void)
+{
+ unsigned int timer_irqs[SAMSUNG_PWM_NUM] = {
+ IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
+ IRQ_TIMER3_VIC, IRQ_TIMER4_VIC,
+ };
+
+ samsung_pwm_clocksource_init(S3C_VA_TIMER,
+ timer_irqs, &s5pc100_pwm_variant);
+}
+
/*
* s5pc100_map_io
*
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 0963283..07cdff7 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -15,7 +15,7 @@ config CPU_S5PV210
select S5P_PM if PM
select S5P_SLEEP if PM
select SAMSUNG_DMADEV
- select SAMSUNG_HRT
+ select CLKSRC_SAMSUNG_PWM
help
Enable S5PV210 CPU support
diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
index 4eba33d..d28affb 100644
--- a/arch/arm/mach-s5pv210/common.c
+++ b/arch/arm/mach-s5pv210/common.c
@@ -157,6 +157,23 @@ static struct samsung_pwm_variant s5pv210_pwm_variant = {
.tclk_mask = (1 << 5),
};
+void __init samsung_set_timer_source(unsigned int event, unsigned int source)
+{
+ s5pv210_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1;
+ s5pv210_pwm_variant.output_mask &= ~(BIT(event) | BIT(source));
+}
+
+void __init samsung_timer_init(void)
+{
+ unsigned int timer_irqs[SAMSUNG_PWM_NUM] = {
+ IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
+ IRQ_TIMER3_VIC, IRQ_TIMER4_VIC,
+ };
+
+ samsung_pwm_clocksource_init(S3C_VA_TIMER,
+ timer_irqs, &s5pv210_pwm_variant);
+}
+
/*
* s5pv210_map_io
*
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 05/15] ARM: SAMSUNG: Remove old samsung-time driver
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (3 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 04/15] ARM: SAMSUNG: Move all platforms to new clocksource driver Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 06/15] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code Tomasz Figa
` (10 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/plat-samsung/Kconfig | 8 -
arch/arm/plat-samsung/Makefile | 1 -
arch/arm/plat-samsung/include/plat/samsung-time.h | 23 --
arch/arm/plat-samsung/samsung-time.c | 394 ----------------------
4 files changed, 426 deletions(-)
delete mode 100644 arch/arm/plat-samsung/samsung-time.c
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index f8ed2de..e88adc0 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -60,14 +60,6 @@ config S3C_LOWLEVEL_UART_PORT
this configuration should be between zero and two. The port
must have been initialised by the boot-loader before use.
-# timer options
-
-config SAMSUNG_HRT
- bool
- select SAMSUNG_DEV_PWM
- help
- Use the High Resolution timer support
-
# clock options
config SAMSUNG_CLOCK
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index a23c460..87494e1 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -12,7 +12,6 @@ obj- :=
# Objects we always build independent of SoC choice
obj-y += init.o cpu.o
-obj-$(CONFIG_SAMSUNG_HRT) += samsung-time.o
obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o
obj-$(CONFIG_SAMSUNG_CLOCK) += pwm-clock.o
diff --git a/arch/arm/plat-samsung/include/plat/samsung-time.h b/arch/arm/plat-samsung/include/plat/samsung-time.h
index 4cc99bb..209464a 100644
--- a/arch/arm/plat-samsung/include/plat/samsung-time.h
+++ b/arch/arm/plat-samsung/include/plat/samsung-time.h
@@ -22,29 +22,6 @@ enum samsung_timer_mode {
SAMSUNG_PWM4,
};
-struct samsung_timer_source {
- unsigned int event_id;
- unsigned int source_id;
-};
-
-/* Be able to sleep for atleast 4 seconds (usually more) */
-#define SAMSUNG_TIMER_MIN_RANGE 4
-
-#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S5PC100)
-#define TCNT_MAX 0xffff
-#define TSCALER_DIV 25
-#define TDIV 50
-#define TSIZE 16
-#else
-#define TCNT_MAX 0xffffffff
-#define TSCALER_DIV 2
-#define TDIV 2
-#define TSIZE 32
-#endif
-
-#define NON_PERIODIC 0
-#define PERIODIC 1
-
extern void __init samsung_set_timer_source(enum samsung_timer_mode event,
enum samsung_timer_mode source);
diff --git a/arch/arm/plat-samsung/samsung-time.c b/arch/arm/plat-samsung/samsung-time.c
deleted file mode 100644
index f899cbc..0000000
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 06/15] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (4 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 05/15] ARM: SAMSUNG: Remove old samsung-time driver Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 07/15] pwm: samsung: Rename to pwm-samsung-legacy Tomasz Figa
` (9 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
From: Tomasz Figa <t.figa@samsung.com>
As the need for an IRQ chip handling PWM timer interrupt chaining is
gone now, this patch removes all the code made unnecessary.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Conflicts:
arch/arm/plat-samsung/irq-vic-timer.c
---
arch/arm/Kconfig | 1 -
arch/arm/mach-exynos/include/mach/irqs.h | 3 +-
arch/arm/mach-s3c64xx/common.c | 4 -
arch/arm/mach-s3c64xx/include/mach/irqs.h | 8 --
arch/arm/mach-s5p64x0/include/mach/irqs.h | 2 -
arch/arm/mach-s5pc100/include/mach/irqs.h | 2 -
arch/arm/mach-s5pv210/include/mach/irqs.h | 2 -
arch/arm/plat-samsung/Kconfig | 6 --
arch/arm/plat-samsung/Makefile | 1 -
arch/arm/plat-samsung/devs.c | 25 ++----
arch/arm/plat-samsung/include/plat/irq-vic-timer.h | 13 ---
arch/arm/plat-samsung/include/plat/irqs.h | 9 --
arch/arm/plat-samsung/irq-vic-timer.c | 98 ----------------------
arch/arm/plat-samsung/s5p-irq.c | 3 -
14 files changed, 7 insertions(+), 170 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/irq-vic-timer.h
delete mode 100644 arch/arm/plat-samsung/irq-vic-timer.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 42d6ea2..66b69a8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -730,7 +730,6 @@ config ARCH_S3C64XX
select S3C_GPIO_TRACK
select SAMSUNG_CLKSRC
select SAMSUNG_GPIOLIB_4BIT
- select SAMSUNG_IRQ_VIC_TIMER
select USB_ARCH_HAS_OHCI
help
Samsung S3C64XX series based systems
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index c72f59d..c8f01db 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -464,10 +464,9 @@
#define S5P_EINT_BASE2 (S5P_EINT_BASE1 + 16)
#define S5P_GPIOINT_BASE (S5P_EINT_BASE1 + 32)
#define IRQ_GPIO_END (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
-#define IRQ_TIMER_BASE (IRQ_GPIO_END + 64)
/* Set the default NR_IRQS */
-#define EXYNOS_NR_IRQS (IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
+#define EXYNOS_NR_IRQS (IRQ_GPIO_END + 64)
#ifndef CONFIG_SPARSE_IRQ
#define NR_IRQS EXYNOS_NR_IRQS
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index add8451..4847e44 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -42,7 +42,6 @@
#include <plat/pm.h>
#include <plat/gpio-cfg.h>
#include <plat/irq-uart.h>
-#include <plat/irq-vic-timer.h>
#include <plat/pwm-core.h>
#include <plat/regs-irqtype.h>
#include <plat/regs-serial.h>
@@ -216,9 +215,6 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
/* initialise the pair of VICs */
vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME);
vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME);
-
- /* add the timer sub-irqs */
- s3c_init_vic_timer_irq(5, IRQ_TIMER0);
}
#define eint_offset(irq) ((irq) - IRQ_EINT(0))
diff --git a/arch/arm/mach-s3c64xx/include/mach/irqs.h b/arch/arm/mach-s3c64xx/include/mach/irqs.h
index 96d60e0..67bbd1d 100644
--- a/arch/arm/mach-s3c64xx/include/mach/irqs.h
+++ b/arch/arm/mach-s3c64xx/include/mach/irqs.h
@@ -107,14 +107,6 @@
#define IRQ_TC IRQ_PENDN
#define IRQ_ADC S3C64XX_IRQ_VIC1(31)
-#define S3C64XX_TIMER_IRQ(x) S3C_IRQ(64 + (x))
-
-#define IRQ_TIMER0 S3C64XX_TIMER_IRQ(0)
-#define IRQ_TIMER1 S3C64XX_TIMER_IRQ(1)
-#define IRQ_TIMER2 S3C64XX_TIMER_IRQ(2)
-#define IRQ_TIMER3 S3C64XX_TIMER_IRQ(3)
-#define IRQ_TIMER4 S3C64XX_TIMER_IRQ(4)
-
/* compatibility for device defines */
#define IRQ_IIC1 IRQ_S3C6410_IIC1
diff --git a/arch/arm/mach-s5p64x0/include/mach/irqs.h b/arch/arm/mach-s5p64x0/include/mach/irqs.h
index 5b845e8..53982db 100644
--- a/arch/arm/mach-s5p64x0/include/mach/irqs.h
+++ b/arch/arm/mach-s5p64x0/include/mach/irqs.h
@@ -141,8 +141,6 @@
#define IRQ_EINT_GROUP(grp, x) (IRQ_EINT_GROUP##grp##_BASE + (x))
-#define IRQ_TIMER_BASE (11)
-
/* Set the default NR_IRQS */
#define NR_IRQS (IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
diff --git a/arch/arm/mach-s5pc100/include/mach/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h
index 2870f12..d2eb475 100644
--- a/arch/arm/mach-s5pc100/include/mach/irqs.h
+++ b/arch/arm/mach-s5pc100/include/mach/irqs.h
@@ -97,8 +97,6 @@
#define IRQ_SDMFIQ S5P_IRQ_VIC2(31)
#define IRQ_VIC_END S5P_IRQ_VIC2(31)
-#define IRQ_TIMER_BASE (11)
-
#define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0))
#define S5P_EINT_BASE2 (IRQ_VIC_END + 1)
diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h
index e777e01..5e0de3a 100644
--- a/arch/arm/mach-s5pv210/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv210/include/mach/irqs.h
@@ -118,8 +118,6 @@
#define IRQ_MDNIE3 S5P_IRQ_VIC3(8)
#define IRQ_VIC_END S5P_IRQ_VIC3(31)
-#define IRQ_TIMER_BASE (11)
-
#define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0))
#define S5P_EINT_BASE2 (IRQ_VIC_END + 1)
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index e88adc0..5c7f9e5 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -27,7 +27,6 @@ config PLAT_S5P
select S5P_GPIO_DRVSTR
select SAMSUNG_CLKSRC if !COMMON_CLK
select SAMSUNG_GPIOLIB_4BIT
- select SAMSUNG_IRQ_VIC_TIMER
help
Base platform code for Samsung's S5P series SoC.
@@ -79,11 +78,6 @@ config S5P_CLOCK
# options for IRQ support
-config SAMSUNG_IRQ_VIC_TIMER
- bool
- help
- Internal configuration to build the VIC timer interrupt code.
-
config S5P_IRQ
def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210)
help
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 87494e1..ae2a0fd 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_SAMSUNG_CLOCK) += pwm-clock.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
-obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.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
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index bba6d78..290f63a 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -1099,22 +1099,9 @@ arch_initcall(s5p_pmu_init);
#ifdef CONFIG_SAMSUNG_DEV_PWM
-#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) \
+#define DEFINE_S3C_TIMER(_tmr_no) \
.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,
@@ -1122,11 +1109,11 @@ arch_initcall(s5p_pmu_init);
*/
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) },
+ [0] = { DEFINE_S3C_TIMER(0) },
+ [1] = { DEFINE_S3C_TIMER(1) },
+ [2] = { DEFINE_S3C_TIMER(2) },
+ [3] = { DEFINE_S3C_TIMER(3) },
+ [4] = { DEFINE_S3C_TIMER(4) },
};
static struct resource samsung_pwm_resource[] = {
diff --git a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
deleted file mode 100644
index 5b9c42f..0000000
diff --git a/arch/arm/plat-samsung/include/plat/irqs.h b/arch/arm/plat-samsung/include/plat/irqs.h
index df46b77..039001c 100644
--- a/arch/arm/plat-samsung/include/plat/irqs.h
+++ b/arch/arm/plat-samsung/include/plat/irqs.h
@@ -44,15 +44,6 @@
#define S5P_IRQ_VIC2(x) (S5P_VIC2_BASE + (x))
#define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x))
-#define S5P_TIMER_IRQ(x) (IRQ_TIMER_BASE + (x))
-
-#define IRQ_TIMER0 S5P_TIMER_IRQ(0)
-#define IRQ_TIMER1 S5P_TIMER_IRQ(1)
-#define IRQ_TIMER2 S5P_TIMER_IRQ(2)
-#define IRQ_TIMER3 S5P_TIMER_IRQ(3)
-#define IRQ_TIMER4 S5P_TIMER_IRQ(4)
-#define IRQ_TIMER_COUNT (5)
-
#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \
: ((x) - 16 + S5P_EINT_BASE2))
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
deleted file mode 100644
index 0fceb42..0000000
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ff1a760..6729cb2 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -19,7 +19,6 @@
#include <mach/map.h>
#include <plat/regs-timer.h>
#include <plat/cpu.h>
-#include <plat/irq-vic-timer.h>
void __init s5p_init_irq(u32 *vic, u32 num_vic)
{
@@ -30,6 +29,4 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
for (irq = 0; irq < num_vic; irq++)
vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
#endif
-
- s3c_init_vic_timer_irq(5, IRQ_TIMER0);
}
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 07/15] pwm: samsung: Rename to pwm-samsung-legacy
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (5 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 06/15] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
` (8 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch renames the old pwm-samsung driver to pwm-samsung-legacy to
create place for the new, rewritten, DT-aware pwm-samsung driver using
Samsung PWM/timer master driver.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
drivers/pwm/Makefile | 2 +-
drivers/pwm/{pwm-samsung.c => pwm-samsung-legacy.c} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename drivers/pwm/{pwm-samsung.c => pwm-samsung-legacy.c} (100%)
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 94ba21e..229a599 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
-obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung-legacy.c
similarity index 100%
rename from drivers/pwm/pwm-samsung.c
rename to drivers/pwm/pwm-samsung-legacy.c
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (6 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 07/15] pwm: samsung: Rename to pwm-samsung-legacy Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-13 20:14 ` Heiko Stübner
` (2 more replies)
2013-06-05 21:18 ` [PATCH 09/15] ARM: SAMSUNG: Rework private data handling in dev-backlight Tomasz Figa
` (7 subsequent siblings)
15 siblings, 3 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch introduces new Samsung PWM driver, which uses Samsung
PWM/timer master driver to control shared parts of the hardware.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-samsung.c | 528 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 529 insertions(+)
create mode 100644 drivers/pwm/pwm-samsung.c
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 229a599..833c3ac 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
+obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
new file mode 100644
index 0000000..61bed3d
--- /dev/null
+++ b/drivers/pwm/pwm-samsung.c
@@ -0,0 +1,528 @@
+/* drivers/pwm/pwm-samsung.c
+ *
+ * Copyright (c) 2007 Ben Dooks
+ * Copyright (c) 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * PWM driver 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 as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#include <clocksource/samsung_pwm.h>
+
+#define REG_TCFG0 0x00
+#define REG_TCFG1 0x04
+#define REG_TCON 0x08
+
+#define REG_TCNTB(tmr) (0x0c + ((tmr) * 0xc))
+#define REG_TCMPB(tmr) (0x10 + ((tmr) * 0xc))
+
+#define TCFG0_PRESCALER_MASK 0xff
+#define TCFG0_PRESCALER1_SHIFT 8
+
+#define TCFG1_MUX_MASK 0xf
+#define TCFG1_SHIFT(x) ((x) * 4)
+
+#define TCON_START(chan) (1 << (4 * (chan) + 0))
+#define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1))
+#define TCON_INVERT(chan) (1 << (4 * (chan) + 2))
+#define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3))
+
+struct samsung_pwm_channel {
+ unsigned long period_ns;
+ unsigned long duty_ns;
+ unsigned long tin_ns;
+};
+
+struct samsung_pwm_chip {
+ struct pwm_chip chip;
+ struct samsung_pwm_variant variant;
+ struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
+
+ void __iomem *base;
+ struct clk *base_clk;
+ struct clk *tclk0;
+ struct clk *tclk1;
+};
+#define to_samsung_pwm_chip(chip) \
+ container_of(chip, struct samsung_pwm_chip, chip)
+
+#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
+static DEFINE_SPINLOCK(samsung_pwm_lock);
+#endif
+
+static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
+ unsigned int channel, u8 divisor)
+{
+ u8 shift = TCFG1_SHIFT(channel);
+ unsigned long flags;
+ u32 reg;
+ u8 bits;
+
+ bits = (fls(divisor) - 1) - pwm->variant.div_base;
+
+ spin_lock_irqsave(&samsung_pwm_lock, flags);
+
+ reg = readl(pwm->base + REG_TCFG1);
+ reg &= ~(TCFG1_MUX_MASK << shift);
+ reg |= bits << shift;
+ writel(reg, pwm->base + REG_TCFG1);
+
+ spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+}
+
+static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
+ unsigned int chan)
+{
+ struct samsung_pwm_variant *variant = &chip->variant;
+ u32 reg;
+
+ reg = readl(chip->base + REG_TCFG1);
+ reg >>= TCFG1_SHIFT(chan);
+ reg &= TCFG1_MUX_MASK;
+
+ return ((1 << reg) & variant->tclk_mask) == 0;
+}
+
+static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip,
+ unsigned int chan)
+{
+ unsigned long rate;
+ u32 reg;
+
+ rate = clk_get_rate(chip->base_clk);
+
+ reg = readl(chip->base + REG_TCFG0);
+ if (chan >= 2)
+ reg >>= TCFG0_PRESCALER1_SHIFT;
+ reg &= TCFG0_PRESCALER_MASK;
+
+ return rate / (reg + 1);
+}
+
+static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
+ unsigned int chan, unsigned long freq)
+{
+ struct samsung_pwm_variant *variant = &chip->variant;
+ unsigned long rate;
+ unsigned int div;
+ struct clk *clk;
+
+ if (!pwm_samsung_is_tdiv(chip, chan)) {
+ clk = (chan < 2) ? chip->tclk0 : chip->tclk1;
+ if (!IS_ERR(clk)) {
+ rate = clk_get_rate(clk);
+ if (rate)
+ return rate;
+ }
+
+ dev_warn(chip->chip.dev,
+ "tclk of PWM %d is inoperational, using tdiv\n", chan);
+ }
+
+ rate = pwm_samsung_get_tin_rate(chip, chan);
+ dev_dbg(chip->chip.dev, "tin parent at %lu\n", rate);
+
+ /*
+ * Compare minimum PWM frequency that can be achieved with possible
+ * divider settings and choose the lowest divisor that can generate
+ * frequencies lower than requested.
+ */
+ for (div = variant->div_base; div < 4; ++div)
+ if ((rate >> (variant->bits + div)) < freq)
+ break;
+
+ pwm_samsung_set_divisor(chip, chan, 1 << div);
+
+ return rate >> div;
+}
+
+static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+
+ if (our_chip->variant.output_mask & (1 << pwm->hwpwm))
+ return 0;
+
+ dev_warn(our_chip->chip.dev,
+ "tried to request PWM channel %d without output\n",
+ pwm->hwpwm);
+
+ return -EINVAL;
+}
+
+static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+ unsigned int channel = pwm->hwpwm;
+ unsigned long tcon;
+ unsigned long flags;
+
+ if (channel > 0)
+ ++channel;
+
+ spin_lock_irqsave(&samsung_pwm_lock, flags);
+
+ tcon = __raw_readl(our_chip->base + REG_TCON);
+
+ tcon &= ~TCON_MANUALUPDATE(channel);
+ tcon |= TCON_START(channel) | TCON_AUTORELOAD(channel);
+
+ __raw_writel(tcon, our_chip->base + REG_TCON);
+
+ spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+
+ return 0;
+}
+
+static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+ unsigned int channel = pwm->hwpwm;
+ unsigned long tcon;
+ unsigned long flags;
+
+ if (channel > 0)
+ ++channel;
+
+ spin_lock_irqsave(&samsung_pwm_lock, flags);
+
+ tcon = __raw_readl(our_chip->base + REG_TCON);
+ tcon &= ~TCON_AUTORELOAD(channel);
+ __raw_writel(tcon, our_chip->base + REG_TCON);
+
+ spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+}
+
+static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+ struct samsung_pwm_channel *chan = &our_chip->channels[pwm->hwpwm];
+ unsigned long tin_ns = chan->tin_ns;
+ unsigned int tcon_chan = pwm->hwpwm;
+ unsigned long tin_rate;
+ unsigned long period;
+ unsigned long flags;
+ unsigned long tcnt;
+ long tcmp;
+ u32 tcon;
+
+ /* We currently avoid using 64bit arithmetic by using the
+ * fact that anything faster than 1Hz is easily representable
+ * by 32bits. */
+ if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
+ return -ERANGE;
+
+ if (period_ns == chan->period_ns && duty_ns == chan->duty_ns)
+ return 0;
+
+ /* The TCMP and TCNT can be read without a lock, they're not
+ * shared between the timers. */
+ tcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm));
+ tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
+
+ period = NSEC_PER_SEC / period_ns;
+
+ dev_dbg(our_chip->chip.dev, "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 (chan->period_ns != period_ns) {
+ tin_rate = pwm_samsung_calc_tin(our_chip, pwm->hwpwm, period);
+
+ chan->period_ns = period_ns;
+
+ dev_dbg(our_chip->chip.dev, "tin_rate=%lu\n", tin_rate);
+
+ tin_ns = NSEC_PER_SEC / tin_rate;
+ tcnt = period_ns / tin_ns;
+
+ chan->tin_ns = tin_ns;
+ }
+
+ /* Note, counters count down */
+ tcmp = duty_ns / tin_ns;
+ tcmp = tcnt - tcmp;
+
+ /* the pwm hw only checks the compare register after a decrement,
+ so the pin never toggles if tcmp = tcnt */
+ if (tcmp == tcnt)
+ tcmp--;
+
+ dev_dbg(our_chip->chip.dev, "tin_ns=%lu, tcmp=%ld/%lu\n",
+ tin_ns, tcmp, tcnt);
+
+ if (tcmp < 0)
+ tcmp = 0;
+
+ /* Update the PWM register block. */
+ if (tcon_chan > 0)
+ ++tcon_chan;
+
+ spin_lock_irqsave(&samsung_pwm_lock, flags);
+
+ tcon = __raw_readl(our_chip->base + REG_TCON);
+
+ tcnt--;
+
+ tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan));
+ tcon |= TCON_MANUALUPDATE(tcon_chan);
+
+ __raw_writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
+ __raw_writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
+ __raw_writel(tcon, our_chip->base + REG_TCON);
+
+ spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+
+ return 0;
+}
+
+static int pwm_samsung_set_polarity(struct pwm_chip *chip,
+ struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+ struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+ unsigned int channel = pwm->hwpwm;
+ unsigned long flags;
+ u32 tcon;
+
+ if (channel > 0)
+ ++channel;
+
+ spin_lock_irqsave(&samsung_pwm_lock, flags);
+
+ tcon = __raw_readl(our_chip->base + REG_TCON);
+
+ /* Invert in hardware means normal polarity of PWM core */
+ if (polarity == PWM_POLARITY_NORMAL)
+ tcon |= TCON_INVERT(channel);
+ else
+ tcon &= ~TCON_INVERT(channel);
+
+ __raw_writel(tcon, our_chip->base + REG_TCON);
+
+ spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+
+ return 0;
+}
+
+static struct pwm_ops pwm_samsung_ops = {
+ .request = pwm_samsung_request,
+ .enable = pwm_samsung_enable,
+ .disable = pwm_samsung_disable,
+ .config = pwm_samsung_config,
+ .set_polarity = pwm_samsung_set_polarity,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_OF
+static const struct samsung_pwm_variant s3c24xx_variant = {
+ .bits = 16,
+ .div_base = 1,
+ .has_tint_cstat = false,
+ .tclk_mask = (1 << 4),
+};
+
+static const struct samsung_pwm_variant s3c64xx_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
+};
+
+static const struct samsung_pwm_variant s5p64x0_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = 0,
+};
+
+static const struct samsung_pwm_variant s5p_variant = {
+ .bits = 32,
+ .div_base = 0,
+ .has_tint_cstat = true,
+ .tclk_mask = (1 << 5),
+};
+
+static const struct of_device_id samsung_pwm_matches[] = {
+ { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
+ { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
+ { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
+ { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
+ { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant },
+ {},
+};
+#endif
+
+static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
+{
+ struct device_node *np = chip->chip.dev->of_node;
+ const struct of_device_id *match;
+ struct property *prop;
+ const __be32 *cur;
+ u32 val;
+
+ match = of_match_node(samsung_pwm_matches, np);
+ if (!match)
+ return -ENODEV;
+
+ memcpy(&chip->variant, match->data, sizeof(chip->variant));
+
+ of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
+ if (val >= SAMSUNG_PWM_NUM) {
+ pr_warning("%s: invalid channel index in samsung,pwm-outputs property\n",
+ __func__);
+ continue;
+ }
+ chip->variant.output_mask |= 1 << val;
+ }
+
+ return 0;
+}
+
+static int pwm_samsung_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct samsung_pwm_chip *chip;
+ struct resource *res;
+ int ret;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ dev_err(dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ chip->chip.dev = &pdev->dev;
+ chip->chip.ops = &pwm_samsung_ops;
+ chip->chip.base = -1;
+ chip->chip.npwm = SAMSUNG_PWM_NUM;
+
+ if (pdev->dev.of_node) {
+ ret = pwm_samsung_parse_dt(chip);
+ if (ret)
+ return ret;
+
+ chip->chip.of_xlate = of_pwm_xlate_with_flags;
+ chip->chip.of_pwm_n_cells = 3;
+ } else {
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ memcpy(&chip->variant, pdev->dev.platform_data,
+ sizeof(chip->variant));
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get mem resource\n");
+ return -ENOMEM;
+ }
+
+ chip->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!chip->base) {
+ dev_err(&pdev->dev, "failed to request and map registers\n");
+ return -ENOMEM;
+ }
+
+ chip->base_clk = devm_clk_get(&pdev->dev, "timers");
+ if (IS_ERR(chip->base_clk)) {
+ dev_err(dev, "failed to get timer base clk\n");
+ return PTR_ERR(chip->base_clk);
+ }
+ clk_prepare_enable(chip->base_clk);
+
+ chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
+ chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
+
+ ret = pwmchip_add(&chip->chip);
+ if (ret < 0) {
+ dev_err(dev, "failed to register pwm\n");
+ goto err_clk_disable;
+ }
+
+ dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1@%lu\n",
+ clk_get_rate(chip->base_clk),
+ !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
+ !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
+
+ platform_set_drvdata(pdev, chip);
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(chip->base_clk);
+
+ return ret;
+}
+
+static int pwm_samsung_remove(struct platform_device *pdev)
+{
+ struct samsung_pwm_chip *chip = platform_get_drvdata(pdev);
+ int err;
+
+ err = pwmchip_remove(&chip->chip);
+ if (err < 0)
+ return err;
+
+ clk_disable_unprepare(chip->base_clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_samsung_suspend(struct device *dev)
+{
+ struct samsung_pwm_chip *chip = dev_get_drvdata(dev);
+ int i;
+
+ /* No one preserve these values during suspend so reset them
+ * Otherwise driver leaves PWM unconfigured if same values
+ * passed to pwm_config
+ */
+ for (i = 0; i < SAMSUNG_PWM_NUM; ++i) {
+ chip->channels[i].period_ns = 0;
+ chip->channels[i].duty_ns = 0;
+ }
+
+ return 0;
+}
+#endif
+
+static struct dev_pm_ops pwm_samsung_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pwm_samsung_suspend, NULL)
+};
+
+static struct platform_driver pwm_samsung_driver = {
+ .driver = {
+ .name = "samsung-pwm",
+ .owner = THIS_MODULE,
+ .pm = &pwm_samsung_pm_ops,
+ .of_match_table = of_match_ptr(samsung_pwm_matches),
+ },
+ .probe = pwm_samsung_probe,
+ .remove = pwm_samsung_remove,
+};
+module_platform_driver(pwm_samsung_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
+MODULE_ALIAS("platform:samsung-pwm");
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 09/15] ARM: SAMSUNG: Rework private data handling in dev-backlight
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (7 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 10/15] ARM: SAMSUNG: Modify board files to use new PWM platform device Tomasz Figa
` (6 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch modifies dev-backlight helpers to get private data using
container_of instead of abusing platform_data field of PWM device.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/plat-samsung/dev-backlight.c | 51 ++++++++++++++++++++---------------
1 file changed, 29 insertions(+), 22 deletions(-)
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index 5f197dc..e467a01 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -20,13 +20,18 @@
#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_device *timer_dev =
- container_of(dev->parent, struct platform_device, dev);
- struct samsung_bl_gpio_info *bl_gpio_info =
- timer_dev->dev.platform_data;
+ 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) {
@@ -42,10 +47,10 @@ static int samsung_bl_init(struct device *dev)
static void samsung_bl_exit(struct device *dev)
{
- struct platform_device *timer_dev =
- container_of(dev->parent, struct platform_device, dev);
- struct samsung_bl_gpio_info *bl_gpio_info =
- timer_dev->dev.platform_data;
+ 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);
@@ -60,12 +65,14 @@ static void samsung_bl_exit(struct device *dev)
* for their specific boards
*/
-static struct platform_pwm_backlight_data samsung_dfl_bl_data __initdata = {
- .max_brightness = 255,
- .dft_brightness = 255,
- .pwm_period_ns = 78770,
- .init = samsung_bl_init,
- .exit = samsung_bl_exit,
+static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = {
+ .plat_data = {
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = samsung_bl_init,
+ .exit = samsung_bl_exit,
+ },
};
static struct platform_device samsung_dfl_bl_device __initdata = {
@@ -82,6 +89,7 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
{
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,
@@ -91,17 +99,19 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
return;
}
- samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data,
- sizeof(struct platform_pwm_backlight_data), samsung_bl_device);
- if (!samsung_bl_data) {
+ 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 =
- &s3c_device_timer[samsung_bl_data->pwm_id].dev;
+ samsung_bl_device->dev.parent = &samsung_device_pwm.dev;
if (bl_data->max_brightness)
samsung_bl_data->max_brightness = bl_data->max_brightness;
@@ -122,9 +132,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
if (bl_data->check_fb)
samsung_bl_data->check_fb = bl_data->check_fb;
- /* Keep the GPIO info for future use */
- s3c_device_timer[samsung_bl_data->pwm_id].dev.platform_data = gpio_info;
-
/* Register the specific PWM timer dev for Backlight control */
ret = platform_device_register(
&s3c_device_timer[samsung_bl_data->pwm_id]);
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 10/15] ARM: SAMSUNG: Modify board files to use new PWM platform device
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (8 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 09/15] ARM: SAMSUNG: Rework private data handling in dev-backlight Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 11/15] pwm: Remove superseded pwm-samsung-legacy driver Tomasz Figa
` (5 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch modifies any board files using the legacy PWM device to use
the new device instead.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/mach-exynos/mach-nuri.c | 4 ++--
arch/arm/mach-exynos/mach-origen.c | 3 ++-
arch/arm/mach-exynos/mach-smdk4x12.c | 3 ++-
arch/arm/mach-exynos/mach-smdkv310.c | 3 ++-
arch/arm/mach-s3c24xx/mach-h1940.c | 4 ++--
arch/arm/mach-s3c24xx/mach-rx1950.c | 5 ++---
arch/arm/mach-s3c64xx/mach-crag6410.c | 4 ++--
arch/arm/mach-s3c64xx/mach-hmt.c | 4 ++--
arch/arm/mach-s3c64xx/mach-smartq.c | 4 ++--
arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 +
arch/arm/mach-s5p64x0/mach-smdk6440.c | 1 +
arch/arm/mach-s5p64x0/mach-smdk6450.c | 1 +
arch/arm/mach-s5pc100/mach-smdkc100.c | 1 +
arch/arm/mach-s5pv210/mach-smdkv210.c | 1 +
arch/arm/plat-samsung/dev-backlight.c | 10 ----------
15 files changed, 23 insertions(+), 26 deletions(-)
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 5c8b287..a5193ed 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -310,7 +310,7 @@ static struct platform_device nuri_backlight_device = {
.name = "pwm-backlight",
.id = -1,
.dev = {
- .parent = &s3c_device_timer[0].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &nuri_backlight_data,
},
};
@@ -1302,7 +1302,7 @@ static struct platform_device *nuri_devices[] __initdata = {
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
&s3c_device_wdt,
- &s3c_device_timer[0],
+ &samsung_device_pwm,
&s5p_device_ehci,
&s3c_device_i2c3,
&i2c9_gpio,
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 27f03ed..d84274c 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -618,7 +618,7 @@ static struct platform_device origen_lcd_hv070wsa = {
};
static struct pwm_lookup origen_pwm_lookup[] = {
- PWM_LOOKUP("s3c24xx-pwm.0", 0, "pwm-backlight.0", NULL),
+ PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight.0", NULL),
};
#ifdef CONFIG_DRM_EXYNOS_FIMD
@@ -693,6 +693,7 @@ static struct platform_device *origen_devices[] __initdata = {
&s3c_device_hsmmc2,
&s3c_device_hsmmc0,
&s3c_device_i2c0,
+ &samsung_device_pwm,
&s3c_device_rtc,
&s3c_device_usb_hsotg,
&s3c_device_wdt,
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index 2c8af96..f854f22 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -224,7 +224,7 @@ static struct platform_pwm_backlight_data smdk4x12_bl_data = {
};
static struct pwm_lookup smdk4x12_pwm_lookup[] = {
- PWM_LOOKUP("s3c24xx-pwm.1", 0, "pwm-backlight.0", NULL),
+ PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL),
};
static uint32_t smdk4x12_keymap[] __initdata = {
@@ -305,6 +305,7 @@ static struct platform_device *smdk4x12_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_i2c3,
&s3c_device_i2c7,
+ &samsung_device_pwm,
&s3c_device_rtc,
&s3c_device_usb_hsotg,
&s3c_device_wdt,
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index d95b8cf..f0c47b5 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -289,6 +289,7 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&s3c_device_hsmmc3,
&s3c_device_i2c1,
&s5p_device_i2c_hdmiphy,
+ &samsung_device_pwm,
&s3c_device_rtc,
&s3c_device_usb_hsotg,
&s3c_device_wdt,
@@ -358,7 +359,7 @@ static struct i2c_board_info hdmiphy_info = {
};
static struct pwm_lookup smdkv310_pwm_lookup[] = {
- PWM_LOOKUP("s3c24xx-pwm.1", 0, "pwm-backlight.0", NULL),
+ PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL),
};
static void s5p_tv_setup(void)
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index af4334d..74dd479 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -512,7 +512,7 @@ static struct platform_pwm_backlight_data backlight_data = {
static struct platform_device h1940_backlight = {
.name = "pwm-backlight",
.dev = {
- .parent = &s3c_device_timer[0].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &backlight_data,
},
.id = -1,
@@ -632,7 +632,7 @@ static struct platform_device *h1940_devices[] __initdata = {
&h1940_device_bluetooth,
&s3c_device_sdi,
&s3c_device_rtc,
- &s3c_device_timer[0],
+ &samsung_device_pwm,
&h1940_backlight,
&h1940_lcd_powerdev,
&s3c_device_adc,
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 44ca018..206b1f7 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -530,7 +530,7 @@ static struct platform_pwm_backlight_data rx1950_backlight_data = {
static struct platform_device rx1950_backlight = {
.name = "pwm-backlight",
.dev = {
- .parent = &s3c_device_timer[0].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &rx1950_backlight_data,
},
};
@@ -717,8 +717,7 @@ static struct platform_device *rx1950_devices[] __initdata = {
&s3c_device_sdi,
&s3c_device_adc,
&s3c_device_ts,
- &s3c_device_timer[0],
- &s3c_device_timer[1],
+ &samsung_device_pwm,
&rx1950_backlight,
&rx1950_device_gpiokeys,
&power_supply,
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 8ad88ac..28889cc 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -120,7 +120,7 @@ static struct platform_device crag6410_backlight_device = {
.name = "pwm-backlight",
.id = -1,
.dev = {
- .parent = &s3c_device_timer[0].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &crag6410_backlight_data,
},
};
@@ -375,7 +375,7 @@ static struct platform_device *crag6410_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
- &s3c_device_timer[0],
+ &samsung_device_pwm,
&s3c64xx_device_iis0,
&s3c64xx_device_iis1,
&samsung_device_keypad,
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index 5b7f357..f39569e 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -123,7 +123,7 @@ static struct platform_pwm_backlight_data hmt_backlight_data = {
static struct platform_device hmt_backlight_device = {
.name = "pwm-backlight",
.dev = {
- .parent = &s3c_device_timer[1].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &hmt_backlight_data,
},
};
@@ -239,7 +239,7 @@ static struct platform_device *hmt_devices[] __initdata = {
&s3c_device_nand,
&s3c_device_fb,
&s3c_device_ohci,
- &s3c_device_timer[1],
+ &samsung_device_pwm,
&hmt_backlight_device,
&hmt_leds_device,
};
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index 58ac990..86d980b 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -157,7 +157,7 @@ static struct platform_pwm_backlight_data smartq_backlight_data = {
static struct platform_device smartq_backlight_device = {
.name = "pwm-backlight",
.dev = {
- .parent = &s3c_device_timer[1].dev,
+ .parent = &samsung_device_pwm.dev,
.platform_data = &smartq_backlight_data,
},
};
@@ -246,7 +246,7 @@ static struct platform_device *smartq_devices[] __initdata = {
&s3c_device_i2c0,
&s3c_device_ohci,
&s3c_device_rtc,
- &s3c_device_timer[1],
+ &samsung_device_pwm,
&s3c_device_ts,
&s3c_device_usb_hsotg,
&s3c64xx_device_iis0,
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index bd3295a..2b54ba0 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -274,6 +274,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_fb,
&s3c_device_ohci,
+ &samsung_device_pwm,
&s3c_device_usb_hsotg,
&s3c64xx_device_iisv4,
&samsung_device_keypad,
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index 73f71a6..db4de76 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -162,6 +162,7 @@ static struct platform_device *smdk6440_devices[] __initdata = {
&s3c_device_rtc,
&s3c_device_i2c0,
&s3c_device_i2c1,
+ &samsung_device_pwm,
&s3c_device_ts,
&s3c_device_wdt,
&s5p6440_device_iis,
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index 18303e1..840bddd 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -180,6 +180,7 @@ static struct platform_device *smdk6450_devices[] __initdata = {
&s3c_device_rtc,
&s3c_device_i2c0,
&s3c_device_i2c1,
+ &samsung_device_pwm,
&s3c_device_ts,
&s3c_device_wdt,
&s5p6450_device_iis0,
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index 8c880f7..dd639ad 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -194,6 +194,7 @@ static struct platform_device *smdkc100_devices[] __initdata = {
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
+ &samsung_device_pwm,
&s3c_device_ts,
&s3c_device_wdt,
&smdkc100_lcd_powerdev,
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index d50b6f1..c642280 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -218,6 +218,7 @@ static struct platform_device *smdkv210_devices[] __initdata = {
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_i2c2,
+ &samsung_device_pwm,
&s3c_device_rtc,
&s3c_device_ts,
&s3c_device_usb_hsotg,
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index e467a01..d51f956 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -132,14 +132,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
if (bl_data->check_fb)
samsung_bl_data->check_fb = bl_data->check_fb;
- /* Register the specific PWM timer dev for Backlight control */
- ret = platform_device_register(
- &s3c_device_timer[samsung_bl_data->pwm_id]);
- if (ret) {
- printk(KERN_ERR "failed to register pwm timer for backlight: %d\n", ret);
- goto err_plat_reg1;
- }
-
/* Register the Backlight dev */
ret = platform_device_register(samsung_bl_device);
if (ret) {
@@ -150,8 +142,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
return;
err_plat_reg2:
- platform_device_unregister(&s3c_device_timer[samsung_bl_data->pwm_id]);
-err_plat_reg1:
kfree(samsung_bl_data);
err_data:
kfree(samsung_bl_device);
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 11/15] pwm: Remove superseded pwm-samsung-legacy driver
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (9 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 10/15] ARM: SAMSUNG: Modify board files to use new PWM platform device Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 12/15] ARM: SAMSUNG: Remove old PWM timer platform devices Tomasz Figa
` (4 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch removes the now unused pwm-samsung-legacy driver, which was
replaced by new pwm-samsung driver.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
drivers/pwm/Makefile | 1 -
drivers/pwm/pwm-samsung-legacy.c | 353 ---------------------------------------
2 files changed, 354 deletions(-)
delete mode 100644 drivers/pwm/pwm-samsung-legacy.c
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 833c3ac..94ba21e 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
-obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/pwm-samsung-legacy.c b/drivers/pwm/pwm-samsung-legacy.c
deleted file mode 100644
index a0ece50..0000000
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 12/15] ARM: SAMSUNG: Remove old PWM timer platform devices
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (10 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 11/15] pwm: Remove superseded pwm-samsung-legacy driver Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 13/15] ARM: SAMSUNG: Remove pwm-clock infrastructure Tomasz Figa
` (3 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch removes old Samsung PWM timer platform devices that are not
used any more.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/plat-samsung/devs.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 290f63a..8ce0ac0 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -1098,24 +1098,6 @@ arch_initcall(s5p_pmu_init);
/* PWM Timer */
#ifdef CONFIG_SAMSUNG_DEV_PWM
-
-#define DEFINE_S3C_TIMER(_tmr_no) \
- .name = "s3c24xx-pwm", \
- .id = _tmr_no, \
-
-/*
- * 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) },
- [1] = { DEFINE_S3C_TIMER(1) },
- [2] = { DEFINE_S3C_TIMER(2) },
- [3] = { DEFINE_S3C_TIMER(3) },
- [4] = { DEFINE_S3C_TIMER(4) },
-};
-
static struct resource samsung_pwm_resource[] = {
DEFINE_RES_MEM(SAMSUNG_PA_TIMER, SZ_4K),
};
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 13/15] ARM: SAMSUNG: Remove pwm-clock infrastructure
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (11 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 12/15] ARM: SAMSUNG: Remove old PWM timer platform devices Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header Tomasz Figa
` (2 subsequent siblings)
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
Since all the used PWM prescalers and dividers configuration has been
moved to appropriate drivers, the pwm-clock infrastructure is now
unused and so this patch removes it.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/mach-s3c24xx/clock-s3c2410.c | 1 -
arch/arm/mach-s3c24xx/clock-s3c2412.c | 1 -
arch/arm/mach-s3c24xx/clock-s3c2416.c | 2 -
arch/arm/mach-s3c24xx/clock-s3c2443.c | 2 -
arch/arm/mach-s3c64xx/clock.c | 2 -
arch/arm/mach-s5p64x0/clock-s5p6440.c | 2 -
arch/arm/mach-s5p64x0/clock-s5p6450.c | 2 -
arch/arm/mach-s5pc100/clock.c | 2 -
arch/arm/mach-s5pv210/clock.c | 1 -
arch/arm/plat-samsung/Makefile | 1 -
arch/arm/plat-samsung/include/plat/clock.h | 4 -
arch/arm/plat-samsung/include/plat/pwm-clock.h | 81 -----
arch/arm/plat-samsung/pwm-clock.c | 474 -------------------------
13 files changed, 575 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/pwm-clock.h
delete mode 100644 arch/arm/plat-samsung/pwm-clock.c
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2410.c b/arch/arm/mach-s3c24xx/clock-s3c2410.c
index 34fffdf..afa0267 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2410.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2410.c
@@ -246,6 +246,5 @@ int __init s3c2410_baseclk_add(void)
(clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
(clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
- s3c_pwmclk_init();
return 0;
}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2412.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c
index 2cc017d..d8f253f 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2412.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2412.c
@@ -757,6 +757,5 @@ int __init s3c2412_baseclk_add(void)
}
clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup));
- s3c_pwmclk_init();
return 0;
}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c
index 036056ce..d421a72 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2416.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2416.c
@@ -168,6 +168,4 @@ void __init s3c2416_init_clocks(int xtal)
s3c24xx_register_clock(&hsmmc0_clk);
clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
- s3c_pwmclk_init();
-
}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c
index 0a53051..76cd31f 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2443.c
@@ -209,6 +209,4 @@ void __init s3c2443_init_clocks(int xtal)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
-
- s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 8499415..c1bcc4a 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -1004,6 +1004,4 @@ void __init s3c64xx_register_clocks(unsigned long xtal,
for (cnt = 0; cnt < ARRAY_SIZE(clksrc_cdev); cnt++)
s3c_register_clksrc(clksrc_cdev[cnt], 1);
clkdev_add_table(s3c64xx_clk_lookup, ARRAY_SIZE(s3c64xx_clk_lookup));
-
- s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 35378152..ae34a1d 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -629,6 +629,4 @@ void __init s5p6440_register_clocks(void)
clkdev_add_table(s5p6440_clk_lookup, ARRAY_SIZE(s5p6440_clk_lookup));
s3c24xx_register_clock(&dummy_apb_pclk);
-
- s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index af384dd..0b3ca2e 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -698,6 +698,4 @@ void __init s5p6450_register_clocks(void)
clkdev_add_table(s5p6450_clk_lookup, ARRAY_SIZE(s5p6450_clk_lookup));
s3c24xx_register_clock(&dummy_apb_pclk);
-
- s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index a206dc3..d0dc10e 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -1358,6 +1358,4 @@ void __init s5pc100_register_clocks(void)
s3c_disable_clocks(clk_cdev[ptr], 1);
s3c24xx_register_clock(&dummy_apb_pclk);
-
- s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index f051f53..ca46372 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -1362,5 +1362,4 @@ void __init s5pv210_register_clocks(void)
for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
s3c_disable_clocks(clk_cdev[ptr], 1);
- s3c_pwmclk_init();
}
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index ae2a0fd..be0a4e8 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -14,7 +14,6 @@ obj- :=
obj-y += init.o cpu.o
obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o
-obj-$(CONFIG_SAMSUNG_CLOCK) += pwm-clock.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index a62753d..254c3dd 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -140,10 +140,6 @@ extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
-/* Init for pwm clock code */
-
-extern void s3c_pwmclk_init(void);
-
/* Global watchdog clock used by arch_wtd_reset() callback */
extern struct clk *s3c2410_wdtclk;
diff --git a/arch/arm/plat-samsung/include/plat/pwm-clock.h b/arch/arm/plat-samsung/include/plat/pwm-clock.h
deleted file mode 100644
index bf6a60e..0000000
diff --git a/arch/arm/plat-samsung/pwm-clock.c b/arch/arm/plat-samsung/pwm-clock.c
deleted file mode 100644
index a35ff3b..0000000
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (12 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 13/15] ARM: SAMSUNG: Remove pwm-clock infrastructure Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-13 20:24 ` Heiko Stübner
2013-06-05 21:18 ` [PATCH 15/15] ARM: SAMSUNG: Remove " Tomasz Figa
2013-06-12 21:48 ` [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
15 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
This patch removes remaining inclusions of plat/regs-timer.h as a
preparation to remove the header.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/mach-s3c64xx/irq-pm.c | 2 --
arch/arm/mach-s5p64x0/pm.c | 3 ---
arch/arm/mach-s5pv210/pm.c | 10 ----------
arch/arm/plat-samsung/s5p-irq.c | 1 -
4 files changed, 16 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c
index 0c7e1d9..c3da1b6 100644
--- a/arch/arm/mach-s3c64xx/irq-pm.c
+++ b/arch/arm/mach-s3c64xx/irq-pm.c
@@ -22,7 +22,6 @@
#include <mach/map.h>
#include <plat/regs-serial.h>
-#include <plat/regs-timer.h>
#include <mach/regs-gpio.h>
#include <plat/cpu.h>
#include <plat/pm.h>
@@ -43,7 +42,6 @@ static struct sleep_save irq_save[] = {
SAVE_ITEM(S3C64XX_EINT0FLTCON2),
SAVE_ITEM(S3C64XX_EINT0FLTCON3),
SAVE_ITEM(S3C64XX_EINT0MASK),
- SAVE_ITEM(S3C64XX_TINT_CSTAT),
};
static struct irq_grp_save {
diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
index 97c2a08a..861e15c 100644
--- a/arch/arm/mach-s5p64x0/pm.c
+++ b/arch/arm/mach-s5p64x0/pm.c
@@ -18,7 +18,6 @@
#include <plat/cpu.h>
#include <plat/pm.h>
-#include <plat/regs-timer.h>
#include <plat/wakeup-mask.h>
#include <mach/regs-clock.h>
@@ -48,8 +47,6 @@ static struct sleep_save s5p64x0_misc_save[] = {
SAVE_ITEM(S5P64X0_MEM0CONSLP1),
SAVE_ITEM(S5P64X0_MEM0DRVCON),
SAVE_ITEM(S5P64X0_MEM1DRVCON),
-
- SAVE_ITEM(S3C64XX_TINT_CSTAT),
};
/* DPLL is present only in S5P6450 */
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 2b68a67..3cf3f9c 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -21,7 +21,6 @@
#include <plat/cpu.h>
#include <plat/pm.h>
-#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <mach/regs-clock.h>
@@ -77,15 +76,6 @@ static struct sleep_save s5pv210_core_save[] = {
/* Clock ETC */
SAVE_ITEM(S5P_CLK_OUT),
SAVE_ITEM(S5P_MDNIE_SEL),
-
- /* PWM Register */
- SAVE_ITEM(S3C2410_TCFG0),
- SAVE_ITEM(S3C2410_TCFG1),
- SAVE_ITEM(S3C64XX_TINT_CSTAT),
- SAVE_ITEM(S3C2410_TCON),
- SAVE_ITEM(S3C2410_TCNTB(0)),
- SAVE_ITEM(S3C2410_TCMPB(0)),
- SAVE_ITEM(S3C2410_TCNTO(0)),
};
static int s5pv210_cpu_suspend(unsigned long arg)
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index 6729cb2..ddfaca9 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -17,7 +17,6 @@
#include <mach/irqs.h>
#include <mach/map.h>
-#include <plat/regs-timer.h>
#include <plat/cpu.h>
void __init s5p_init_irq(u32 *vic, u32 num_vic)
--
1.8.2.1
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 15/15] ARM: SAMSUNG: Remove plat/regs-timer.h header
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (13 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header Tomasz Figa
@ 2013-06-05 21:18 ` Tomasz Figa
2013-06-12 21:48 ` [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
15 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-05 21:18 UTC (permalink / raw)
To: linux-arm-kernel
Since all uses of the header has been removed by previous patches it can
be removed safely.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
arch/arm/plat-samsung/include/plat/regs-timer.h | 124 ------------------------
1 file changed, 124 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-timer.h
diff --git a/arch/arm/plat-samsung/include/plat/regs-timer.h b/arch/arm/plat-samsung/include/plat/regs-timer.h
deleted file mode 100644
index d097d92..0000000
--
1.8.2.1
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
` (14 preceding siblings ...)
2013-06-05 21:18 ` [PATCH 15/15] ARM: SAMSUNG: Remove " Tomasz Figa
@ 2013-06-12 21:48 ` Tomasz Figa
2013-06-12 23:00 ` Olof Johansson
15 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-12 21:48 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On Wednesday 05 of June 2013 23:18:05 Tomasz Figa wrote:
> Since we now have a proper Samsung PWM clocksource driver in place,
> we can proceed with further cleanup of PWM timers support on Samsung
> SoCs.
>
> This series attempts to achieve this goal by:
> 1) moving remaining Samsung platforms to the new clocksource driver
> 2) removing old clocksource driver
> 3) adding new multiplatform- and DT-aware PWM driver
> 4) moving all Samsung platforms to use the new PWM driver
> 5) removing old PWM driver
> 6) removing all PWM-related code that is not used anymore
>
> Cleaning up the PWM driver is a bit tricky, because the design of
> current driver makes it completely unsuitable for DT and multiplatform
> and would require a heavy rework to make it usable, breaking any
> existing Samsung PWM users by the way. To avoid any breakage I decided
> to keep the old driver, add new one, move all platforms to it and then
> remove the old one.
>
> See particular patches for more detailed descriptions.
>
> On S3C6410-based Tiny6410 (Mini6410-compatible), after enabling
> pwm-beeper:
>
> Tested-by: Tomasz Figa <tomasz.figa@gmail.com>
>
> Needs testing on other platforms as I could only compile test for them.
>
> Tomasz Figa (15):
> ARM: SAMSUNG: Unify base address definitions of timer block
> ARM: SAMSUNG: Add new PWM platform device
> ARM: SAMSUNG: Set PWM platform data
> ARM: SAMSUNG: Move all platforms to new clocksource driver
> ARM: SAMSUNG: Remove old samsung-time driver
> ARM: SAMSUNG: Remove unused PWM timer IRQ chip code
> pwm: samsung: Rename to pwm-samsung-legacy
> pwm: Add new pwm-samsung driver
> ARM: SAMSUNG: Rework private data handling in dev-backlight
> ARM: SAMSUNG: Modify board files to use new PWM platform device
> pwm: Remove superseded pwm-samsung-legacy driver
> ARM: SAMSUNG: Remove old PWM timer platform devices
> ARM: SAMSUNG: Remove pwm-clock infrastructure
> ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
> ARM: SAMSUNG: Remove plat/regs-timer.h header
>
> arch/arm/Kconfig | 1 -
> arch/arm/mach-exynos/common.c | 3 +
> arch/arm/mach-exynos/include/mach/irqs.h | 3 +-
> arch/arm/mach-exynos/include/mach/map.h | 1 +
> arch/arm/mach-exynos/mach-nuri.c | 4 +-
> arch/arm/mach-exynos/mach-origen.c | 3 +-
> arch/arm/mach-exynos/mach-smdk4x12.c | 3 +-
> arch/arm/mach-exynos/mach-smdkv310.c | 3 +-
> arch/arm/mach-s3c24xx/Kconfig | 12 +-
> arch/arm/mach-s3c24xx/clock-s3c2410.c | 1 -
> arch/arm/mach-s3c24xx/clock-s3c2412.c | 1 -
> arch/arm/mach-s3c24xx/clock-s3c2416.c | 2 -
> arch/arm/mach-s3c24xx/clock-s3c2443.c | 2 -
> arch/arm/mach-s3c24xx/common.c | 27 +
> arch/arm/mach-s3c24xx/include/mach/map.h | 2 +
> arch/arm/mach-s3c24xx/mach-h1940.c | 4 +-
> arch/arm/mach-s3c24xx/mach-rx1950.c | 5 +-
> arch/arm/mach-s3c64xx/Kconfig | 4 +-
> arch/arm/mach-s3c64xx/clock.c | 2 -
> arch/arm/mach-s3c64xx/common.c | 32 +-
> arch/arm/mach-s3c64xx/include/mach/irqs.h | 8 -
> arch/arm/mach-s3c64xx/include/mach/map.h | 1 +
> arch/arm/mach-s3c64xx/irq-pm.c | 2 -
> arch/arm/mach-s3c64xx/mach-crag6410.c | 4 +-
> arch/arm/mach-s3c64xx/mach-hmt.c | 4 +-
> arch/arm/mach-s3c64xx/mach-smartq.c | 4 +-
> arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 +
> arch/arm/mach-s5p64x0/Kconfig | 4 +-
> arch/arm/mach-s5p64x0/clock-s5p6440.c | 2 -
> arch/arm/mach-s5p64x0/clock-s5p6450.c | 2 -
> arch/arm/mach-s5p64x0/common.c | 27 +
> arch/arm/mach-s5p64x0/include/mach/irqs.h | 2 -
> arch/arm/mach-s5p64x0/include/mach/map.h | 1 +
> arch/arm/mach-s5p64x0/mach-smdk6440.c | 1 +
> arch/arm/mach-s5p64x0/mach-smdk6450.c | 1 +
> arch/arm/mach-s5p64x0/pm.c | 3 -
> arch/arm/mach-s5pc100/Kconfig | 2 +-
> arch/arm/mach-s5pc100/clock.c | 2 -
> arch/arm/mach-s5pc100/common.c | 28 +
> arch/arm/mach-s5pc100/include/mach/irqs.h | 2 -
> arch/arm/mach-s5pc100/include/mach/map.h | 1 +
> arch/arm/mach-s5pc100/mach-smdkc100.c | 1 +
> arch/arm/mach-s5pv210/Kconfig | 2 +-
> arch/arm/mach-s5pv210/clock.c | 1 -
> arch/arm/mach-s5pv210/common.c | 28 +
> arch/arm/mach-s5pv210/include/mach/irqs.h | 2 -
> arch/arm/mach-s5pv210/include/mach/map.h | 1 +
> arch/arm/mach-s5pv210/mach-smdkv210.c | 1 +
> arch/arm/mach-s5pv210/pm.c | 10 -
> arch/arm/plat-samsung/Kconfig | 14 -
> arch/arm/plat-samsung/Makefile | 3 -
> arch/arm/plat-samsung/dev-backlight.c | 61 ++-
> arch/arm/plat-samsung/devs.c | 42 +-
> arch/arm/plat-samsung/include/plat/clock.h | 4 -
> arch/arm/plat-samsung/include/plat/devs.h | 1 +
> arch/arm/plat-samsung/include/plat/irq-vic-timer.h | 13 -
> arch/arm/plat-samsung/include/plat/irqs.h | 9 -
> arch/arm/plat-samsung/include/plat/pwm-clock.h | 81 ---
> arch/arm/plat-samsung/include/plat/pwm-core.h | 24 +
> arch/arm/plat-samsung/include/plat/regs-timer.h | 124 -----
> arch/arm/plat-samsung/include/plat/samsung-time.h | 23 -
> arch/arm/plat-samsung/irq-vic-timer.c | 98 ----
> arch/arm/plat-samsung/pwm-clock.c | 474
> ----------------- arch/arm/plat-samsung/s5p-irq.c |
> 4 -
> arch/arm/plat-samsung/samsung-time.c | 394 --------------
> drivers/pwm/pwm-samsung.c | 575
> ++++++++++++++------- 66 files changed, 627 insertions(+), 1580
> deletions(-)
> delete mode 100644 arch/arm/plat-samsung/include/plat/irq-vic-timer.h
> delete mode 100644 arch/arm/plat-samsung/include/plat/pwm-clock.h
> create mode 100644 arch/arm/plat-samsung/include/plat/pwm-core.h
> delete mode 100644 arch/arm/plat-samsung/include/plat/regs-timer.h
> delete mode 100644 arch/arm/plat-samsung/irq-vic-timer.c
> delete mode 100644 arch/arm/plat-samsung/pwm-clock.c
> delete mode 100644 arch/arm/plat-samsung/samsung-time.c
Any comments for this series?
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 21:48 ` [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
@ 2013-06-12 23:00 ` Olof Johansson
2013-06-12 23:13 ` Tomasz Figa
2013-06-13 0:25 ` Kukjin Kim
0 siblings, 2 replies; 51+ messages in thread
From: Olof Johansson @ 2013-06-12 23:00 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> > Needs testing on other platforms as I could only compile test for them.
How/who can help here? WHo has and still cares for other affected platforms?
> > 66 files changed, 627 insertions(+), 1580 deletions(-)
Nice cleanup.
> Any comments for this series?
Yes, above. :) In general looks good -- testing coverage is a bit of a concern.
-Olof
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 23:00 ` Olof Johansson
@ 2013-06-12 23:13 ` Tomasz Figa
2013-06-12 23:38 ` Heiko Stübner
2013-06-13 0:25 ` Kukjin Kim
1 sibling, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-12 23:13 UTC (permalink / raw)
To: linux-arm-kernel
Hi Olof,
On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> > > Needs testing on other platforms as I could only compile test for
> > > them.
>
> How/who can help here? WHo has and still cares for other affected
> platforms?
> > > 66 files changed, 627 insertions(+), 1580 deletions(-)
I will try to test this on Exynos 4 at work, if I somehow manage to find
any way to use PWM on our boards (other than already-tested PWM
clocksource).
Unfortunately, except S3C6410, I don't have access to other platforms, or
at least I won't in any reasonable time.
If I remember correctly, in case of my watchdog support cleanup, Kukjin
has been able to test it on S5P64x0.
Heiko and Sylwester used to have some s3c24xx-based boards, not sure if
they still do and are interested in their support in mainline.
So all left is S5PC100 (for which I couldn't find anyone who cares) and
Exynos5.
> Nice cleanup.
Thanks.
> > Any comments for this series?
>
> Yes, above. :) In general looks good -- testing coverage is a bit of a
> concern.
Yeah. Unfortunately all I could do was testing on Tiny6410 and compile
testing on others. I hope we find some really helpful people over here who
could waste a bit of their precious time for this museum. ;)
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 23:13 ` Tomasz Figa
@ 2013-06-12 23:38 ` Heiko Stübner
2013-06-12 23:52 ` Sylwester Nawrocki
0 siblings, 1 reply; 51+ messages in thread
From: Heiko Stübner @ 2013-06-12 23:38 UTC (permalink / raw)
To: linux-arm-kernel
Am Donnerstag, 13. Juni 2013, 01:13:47 schrieb Tomasz Figa:
> Hi Olof,
>
> On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
> > On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> > > > Needs testing on other platforms as I could only compile test for
> > > > them.
> >
> > How/who can help here? WHo has and still cares for other affected
> > platforms?
> >
> > > > 66 files changed, 627 insertions(+), 1580 deletions(-)
>
> I will try to test this on Exynos 4 at work, if I somehow manage to find
> any way to use PWM on our boards (other than already-tested PWM
> clocksource).
>
> Unfortunately, except S3C6410, I don't have access to other platforms, or
> at least I won't in any reasonable time.
>
> If I remember correctly, in case of my watchdog support cleanup, Kukjin
> has been able to test it on S5P64x0.
>
> Heiko and Sylwester used to have some s3c24xx-based boards, not sure if
> they still do and are interested in their support in mainline.
>
> So all left is S5PC100 (for which I couldn't find anyone who cares) and
> Exynos5.
>
> > Nice cleanup.
>
> Thanks.
>
> > > Any comments for this series?
> >
> > Yes, above. :) In general looks good -- testing coverage is a bit of a
> > concern.
>
> Yeah. Unfortunately all I could do was testing on Tiny6410 and compile
> testing on others. I hope we find some really helpful people over here who
> could waste a bit of their precious time for this museum. ;)
I'll try to give it a testrun tomorrow. And my s3c2416 will always be the
first-love-architecture for me ;-)
Heiko
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 23:38 ` Heiko Stübner
@ 2013-06-12 23:52 ` Sylwester Nawrocki
2013-06-13 9:07 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Sylwester Nawrocki @ 2013-06-12 23:52 UTC (permalink / raw)
To: linux-arm-kernel
On 06/13/2013 01:38 AM, Heiko St?bner wrote:
> Am Donnerstag, 13. Juni 2013, 01:13:47 schrieb Tomasz Figa:
>> Hi Olof,
>>
>> On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
>>> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
>>>>> Needs testing on other platforms as I could only compile test for
>>>>> them.
>>>
>>> How/who can help here? WHo has and still cares for other affected
>>> platforms?
>>>
>>>>> 66 files changed, 627 insertions(+), 1580 deletions(-)
>>
>> I will try to test this on Exynos 4 at work, if I somehow manage to find
>> any way to use PWM on our boards (other than already-tested PWM
>> clocksource).
>>
>> Unfortunately, except S3C6410, I don't have access to other platforms, or
>> at least I won't in any reasonable time.
>>
>> If I remember correctly, in case of my watchdog support cleanup, Kukjin
>> has been able to test it on S5P64x0.
>>
>> Heiko and Sylwester used to have some s3c24xx-based boards, not sure if
>> they still do and are interested in their support in mainline.
>>
>> So all left is S5PC100 (for which I couldn't find anyone who cares) and
>> Exynos5.
>>
>>> Nice cleanup.
>>
>> Thanks.
>>
>>>> Any comments for this series?
>>>
>>> Yes, above. :) In general looks good -- testing coverage is a bit of a
>>> concern.
>>
>> Yeah. Unfortunately all I could do was testing on Tiny6410 and compile
>> testing on others. I hope we find some really helpful people over here who
>> could waste a bit of their precious time for this museum. ;)
>
> I'll try to give it a testrun tomorrow. And my s3c2416 will always be the
> first-love-architecture for me ;-)
I'll likely test it tomorrow on a Mini2440 board, I was going to do it
earlier
but got distracted by plenty other things that needed attention too. At
least
that's one of the reasons I got the board - testing the cross-platform
cleanups
and ensuring they are not breaking the older platforms.
Regards,
Sylwester
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 23:00 ` Olof Johansson
2013-06-12 23:13 ` Tomasz Figa
@ 2013-06-13 0:25 ` Kukjin Kim
1 sibling, 0 replies; 51+ messages in thread
From: Kukjin Kim @ 2013-06-13 0:25 UTC (permalink / raw)
To: linux-arm-kernel
Olof Johansson wrote:
>
> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
>
> > > Needs testing on other platforms as I could only compile test for
them.
>
> How/who can help here? WHo has and still cares for other affected
> platforms?
>
> > > 66 files changed, 627 insertions(+), 1580 deletions(-)
>
> Nice cleanup.
>
> > Any comments for this series?
>
> Yes, above. :) In general looks good -- testing coverage is a bit of a
> concern.
>
Good news, I'm building up team to support samsung stuff in mainline
including test on boards, you know, I have the most of smdk/ssdk boards :)
But I need some time :(
I looked at reply from Sylwester and Heiko, thanks. Let me pick this series
after their test.
Thanks.
- Kukjin
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-12 23:52 ` Sylwester Nawrocki
@ 2013-06-13 9:07 ` Tomasz Figa
2013-06-13 20:17 ` Heiko Stübner
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-13 9:07 UTC (permalink / raw)
To: linux-arm-kernel
Hi Heiko, Sylwester,
On Thursday 13 of June 2013 01:52:05 Sylwester Nawrocki wrote:
> On 06/13/2013 01:38 AM, Heiko St?bner wrote:
> > Am Donnerstag, 13. Juni 2013, 01:13:47 schrieb Tomasz Figa:
> >> Hi Olof,
> >>
> >> On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
> >>> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> >>>>> Needs testing on other platforms as I could only compile test for
> >>>>> them.
> >>>
> >>> How/who can help here? WHo has and still cares for other affected
> >>> platforms?
> >>>
> >>>>> 66 files changed, 627 insertions(+), 1580 deletions(-)
> >>
> >> I will try to test this on Exynos 4 at work, if I somehow manage to
> >> find any way to use PWM on our boards (other than already-tested PWM
> >> clocksource).
> >>
> >> Unfortunately, except S3C6410, I don't have access to other
> >> platforms, or at least I won't in any reasonable time.
> >>
> >> If I remember correctly, in case of my watchdog support cleanup,
> >> Kukjin
> >> has been able to test it on S5P64x0.
> >>
> >> Heiko and Sylwester used to have some s3c24xx-based boards, not sure
> >> if
> >> they still do and are interested in their support in mainline.
> >>
> >> So all left is S5PC100 (for which I couldn't find anyone who cares)
> >> and
> >> Exynos5.
> >>
> >>> Nice cleanup.
> >>
> >> Thanks.
> >>
> >>>> Any comments for this series?
> >>>
> >>> Yes, above. :) In general looks good -- testing coverage is a bit of
> >>> a
> >>> concern.
> >>
> >> Yeah. Unfortunately all I could do was testing on Tiny6410 and
> >> compile
> >> testing on others. I hope we find some really helpful people over
> >> here who could waste a bit of their precious time for this museum.
> >> ;)
> >
> > I'll try to give it a testrun tomorrow. And my s3c2416 will always be
> > the first-love-architecture for me ;-)
>
> I'll likely test it tomorrow on a Mini2440 board, I was going to do it
> earlier
> but got distracted by plenty other things that needed attention too. At
> least
> that's one of the reasons I got the board - testing the cross-platform
> cleanups
> and ensuring they are not breaking the older platforms.
Thank you both for your support. Looking forward for testing results :)
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
@ 2013-06-13 20:14 ` Heiko Stübner
2013-06-13 20:18 ` Tomasz Figa
2013-06-16 17:19 ` Tomasz Figa
2013-06-17 20:29 ` Thierry Reding
2 siblings, 1 reply; 51+ messages in thread
From: Heiko Stübner @ 2013-06-13 20:14 UTC (permalink / raw)
To: linux-arm-kernel
Am Mittwoch, 5. Juni 2013, 23:18:13 schrieb Tomasz Figa:
> This patch introduces new Samsung PWM driver, which uses Samsung
> PWM/timer master driver to control shared parts of the hardware.
>
> Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> ---
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-samsung.c | 528
> ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> insertions(+)
> create mode 100644 drivers/pwm/pwm-samsung.c
>
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
[...]
> +static int pwm_samsung_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct samsung_pwm_chip *chip;
> + struct resource *res;
> + int ret;
> +
> + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> + if (chip == NULL) {
> + dev_err(dev, "failed to allocate driver data\n");
> + return -ENOMEM;
> + }
> +
> + chip->chip.dev = &pdev->dev;
> + chip->chip.ops = &pwm_samsung_ops;
> + chip->chip.base = -1;
> + chip->chip.npwm = SAMSUNG_PWM_NUM;
> +
> + if (pdev->dev.of_node) {
> + ret = pwm_samsung_parse_dt(chip);
> + if (ret)
> + return ret;
> +
> + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> + chip->chip.of_pwm_n_cells = 3;
> + } else {
> + if (!pdev->dev.platform_data) {
> + dev_err(&pdev->dev, "no platform data specified\n");
> + return -EINVAL;
> + }
> +
> + memcpy(&chip->variant, pdev->dev.platform_data,
> + sizeof(chip->variant));
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get mem resource\n");
> + return -ENOMEM;
> + }
> +
> + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> + if (!chip->base) {
> + dev_err(&pdev->dev, "failed to request and map registers\n");
> + return -ENOMEM;
> + }
> +
> + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> + if (IS_ERR(chip->base_clk)) {
> + dev_err(dev, "failed to get timer base clk\n");
> + return PTR_ERR(chip->base_clk);
> + }
> + clk_prepare_enable(chip->base_clk);
> +
> + chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
> + chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
> +
> + ret = pwmchip_add(&chip->chip);
> + if (ret < 0) {
> + dev_err(dev, "failed to register pwm\n");
> + goto err_clk_disable;
> + }
> +
> + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> + clk_get_rate(chip->base_clk),
> + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
hmm, these values simply tell some internal state of the pwm, so wouldn't a
dev_dbg be more appropriate?
> +
> + platform_set_drvdata(pdev, chip);
> +
> + return 0;
> +
> +err_clk_disable:
> + clk_disable_unprepare(chip->base_clk);
> +
> + return ret;
> +}
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-13 9:07 ` Tomasz Figa
@ 2013-06-13 20:17 ` Heiko Stübner
2013-06-13 22:27 ` Heiko Stübner
0 siblings, 1 reply; 51+ messages in thread
From: Heiko Stübner @ 2013-06-13 20:17 UTC (permalink / raw)
To: linux-arm-kernel
Am Donnerstag, 13. Juni 2013, 11:07:38 schrieb Tomasz Figa:
> Hi Heiko, Sylwester,
>
> On Thursday 13 of June 2013 01:52:05 Sylwester Nawrocki wrote:
> > On 06/13/2013 01:38 AM, Heiko St?bner wrote:
> > > Am Donnerstag, 13. Juni 2013, 01:13:47 schrieb Tomasz Figa:
> > >> Hi Olof,
> > >>
> > >> On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
> > >>> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> > >>>>> Needs testing on other platforms as I could only compile test for
> > >>>>> them.
> > >>>
> > >>> How/who can help here? WHo has and still cares for other affected
> > >>> platforms?
> > >>>
> > >>>>> 66 files changed, 627 insertions(+), 1580 deletions(-)
> > >>
> > >> I will try to test this on Exynos 4 at work, if I somehow manage to
> > >> find any way to use PWM on our boards (other than already-tested PWM
> > >> clocksource).
> > >>
> > >> Unfortunately, except S3C6410, I don't have access to other
> > >> platforms, or at least I won't in any reasonable time.
> > >>
> > >> If I remember correctly, in case of my watchdog support cleanup,
> > >> Kukjin
> > >> has been able to test it on S5P64x0.
> > >>
> > >> Heiko and Sylwester used to have some s3c24xx-based boards, not sure
> > >> if
> > >> they still do and are interested in their support in mainline.
> > >>
> > >> So all left is S5PC100 (for which I couldn't find anyone who cares)
> > >> and
> > >> Exynos5.
> > >>
> > >>> Nice cleanup.
> > >>
> > >> Thanks.
> > >>
> > >>>> Any comments for this series?
> > >>>
> > >>> Yes, above. :) In general looks good -- testing coverage is a bit of
> > >>> a
> > >>> concern.
> > >>
> > >> Yeah. Unfortunately all I could do was testing on Tiny6410 and
> > >> compile
> > >> testing on others. I hope we find some really helpful people over
> > >> here who could waste a bit of their precious time for this museum.
> > >> ;)
> > >
> > > I'll try to give it a testrun tomorrow. And my s3c2416 will always be
> > > the first-love-architecture for me ;-)
> >
> > I'll likely test it tomorrow on a Mini2440 board, I was going to do it
> > earlier
> > but got distracted by plenty other things that needed attention too. At
> > least
> > that's one of the reasons I got the board - testing the cross-platform
> > cleanups
> > and ensuring they are not breaking the older platforms.
>
> Thank you both for your support. Looking forward for testing results :)
on a s3c2416-based machine for dt and non-dt case
[with the limit that my machine does not has anything connected to the pwm
outputs, so I only get to test the base-pwm and timer part]
Tested-by: Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-13 20:14 ` Heiko Stübner
@ 2013-06-13 20:18 ` Tomasz Figa
0 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-13 20:18 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 13 of June 2013 22:14:19 Heiko St?bner wrote:
> Am Mittwoch, 5. Juni 2013, 23:18:13 schrieb Tomasz Figa:
> > This patch introduces new Samsung PWM driver, which uses Samsung
> > PWM/timer master driver to control shared parts of the hardware.
> >
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> > ---
> >
> > drivers/pwm/Makefile | 1 +
> > drivers/pwm/pwm-samsung.c | 528
> >
> > ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> > insertions(+)
> >
> > create mode 100644 drivers/pwm/pwm-samsung.c
> >
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>
> [...]
>
> > +static int pwm_samsung_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct samsung_pwm_chip *chip;
> > + struct resource *res;
> > + int ret;
> > +
> > + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> > + if (chip == NULL) {
> > + dev_err(dev, "failed to allocate driver data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->chip.dev = &pdev->dev;
> > + chip->chip.ops = &pwm_samsung_ops;
> > + chip->chip.base = -1;
> > + chip->chip.npwm = SAMSUNG_PWM_NUM;
> > +
> > + if (pdev->dev.of_node) {
> > + ret = pwm_samsung_parse_dt(chip);
> > + if (ret)
> > + return ret;
> > +
> > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > + chip->chip.of_pwm_n_cells = 3;
> > + } else {
> > + if (!pdev->dev.platform_data) {
> > + dev_err(&pdev->dev, "no platform data
specified\n");
> > + return -EINVAL;
> > + }
> > +
> > + memcpy(&chip->variant, pdev->dev.platform_data,
> > + sizeof(chip-
>variant));
> > + }
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + if (!res) {
> > + dev_err(&pdev->dev, "failed to get mem resource\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> > + if (!chip->base) {
> > + dev_err(&pdev->dev, "failed to request and map
registers\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> > + if (IS_ERR(chip->base_clk)) {
> > + dev_err(dev, "failed to get timer base clk\n");
> > + return PTR_ERR(chip->base_clk);
> > + }
> > + clk_prepare_enable(chip->base_clk);
> > +
> > + chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
> > + chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
> > +
> > + ret = pwmchip_add(&chip->chip);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to register pwm\n");
> > + goto err_clk_disable;
> > + }
> > +
> > + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> > + clk_get_rate(chip->base_clk),
> > + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> > + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
>
> hmm, these values simply tell some internal state of the pwm, so
> wouldn't a dev_dbg be more appropriate?
Hmm, I have kept it as dev_info as in old driver, but now as you say it,
dev_dbg might be more appropriate indeed, as it isn't really anything
important that users should know...
Best regards,
Tomasz
> > +
> > + platform_set_drvdata(pdev, chip);
> > +
> > + return 0;
> > +
> > +err_clk_disable:
> > + clk_disable_unprepare(chip->base_clk);
> > +
> > + return ret;
> > +}
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
2013-06-05 21:18 ` [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header Tomasz Figa
@ 2013-06-13 20:24 ` Heiko Stübner
2013-06-13 20:38 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Heiko Stübner @ 2013-06-13 20:24 UTC (permalink / raw)
To: linux-arm-kernel
Am Mittwoch, 5. Juni 2013, 23:18:19 schrieb Tomasz Figa:
> This patch removes remaining inclusions of plat/regs-timer.h as a
> preparation to remove the header.
hmm, the patch does a bit more than that, as it also removes the saving of the
registers from the suspend calls, which is most likely handled by the driver
now. But the description should possibly reflect that.
> Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> ---
> arch/arm/mach-s3c64xx/irq-pm.c | 2 --
> arch/arm/mach-s5p64x0/pm.c | 3 ---
> arch/arm/mach-s5pv210/pm.c | 10 ----------
> arch/arm/plat-samsung/s5p-irq.c | 1 -
> 4 files changed, 16 deletions(-)
>
> diff --git a/arch/arm/mach-s3c64xx/irq-pm.c
> b/arch/arm/mach-s3c64xx/irq-pm.c index 0c7e1d9..c3da1b6 100644
> --- a/arch/arm/mach-s3c64xx/irq-pm.c
> +++ b/arch/arm/mach-s3c64xx/irq-pm.c
> @@ -22,7 +22,6 @@
> #include <mach/map.h>
>
> #include <plat/regs-serial.h>
> -#include <plat/regs-timer.h>
> #include <mach/regs-gpio.h>
> #include <plat/cpu.h>
> #include <plat/pm.h>
> @@ -43,7 +42,6 @@ static struct sleep_save irq_save[] = {
> SAVE_ITEM(S3C64XX_EINT0FLTCON2),
> SAVE_ITEM(S3C64XX_EINT0FLTCON3),
> SAVE_ITEM(S3C64XX_EINT0MASK),
> - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> };
>
> static struct irq_grp_save {
> diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
> index 97c2a08a..861e15c 100644
> --- a/arch/arm/mach-s5p64x0/pm.c
> +++ b/arch/arm/mach-s5p64x0/pm.c
> @@ -18,7 +18,6 @@
>
> #include <plat/cpu.h>
> #include <plat/pm.h>
> -#include <plat/regs-timer.h>
> #include <plat/wakeup-mask.h>
>
> #include <mach/regs-clock.h>
> @@ -48,8 +47,6 @@ static struct sleep_save s5p64x0_misc_save[] = {
> SAVE_ITEM(S5P64X0_MEM0CONSLP1),
> SAVE_ITEM(S5P64X0_MEM0DRVCON),
> SAVE_ITEM(S5P64X0_MEM1DRVCON),
> -
> - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> };
>
> /* DPLL is present only in S5P6450 */
> diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
> index 2b68a67..3cf3f9c 100644
> --- a/arch/arm/mach-s5pv210/pm.c
> +++ b/arch/arm/mach-s5pv210/pm.c
> @@ -21,7 +21,6 @@
>
> #include <plat/cpu.h>
> #include <plat/pm.h>
> -#include <plat/regs-timer.h>
>
> #include <mach/regs-irq.h>
> #include <mach/regs-clock.h>
> @@ -77,15 +76,6 @@ static struct sleep_save s5pv210_core_save[] = {
> /* Clock ETC */
> SAVE_ITEM(S5P_CLK_OUT),
> SAVE_ITEM(S5P_MDNIE_SEL),
> -
> - /* PWM Register */
> - SAVE_ITEM(S3C2410_TCFG0),
> - SAVE_ITEM(S3C2410_TCFG1),
> - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> - SAVE_ITEM(S3C2410_TCON),
> - SAVE_ITEM(S3C2410_TCNTB(0)),
> - SAVE_ITEM(S3C2410_TCMPB(0)),
> - SAVE_ITEM(S3C2410_TCNTO(0)),
> };
>
> static int s5pv210_cpu_suspend(unsigned long arg)
> diff --git a/arch/arm/plat-samsung/s5p-irq.c
> b/arch/arm/plat-samsung/s5p-irq.c index 6729cb2..ddfaca9 100644
> --- a/arch/arm/plat-samsung/s5p-irq.c
> +++ b/arch/arm/plat-samsung/s5p-irq.c
> @@ -17,7 +17,6 @@
>
> #include <mach/irqs.h>
> #include <mach/map.h>
> -#include <plat/regs-timer.h>
> #include <plat/cpu.h>
>
> void __init s5p_init_irq(u32 *vic, u32 num_vic)
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
2013-06-13 20:24 ` Heiko Stübner
@ 2013-06-13 20:38 ` Tomasz Figa
0 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-13 20:38 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 13 of June 2013 22:24:33 Heiko St?bner wrote:
> Am Mittwoch, 5. Juni 2013, 23:18:19 schrieb Tomasz Figa:
> > This patch removes remaining inclusions of plat/regs-timer.h as a
> > preparation to remove the header.
>
> hmm, the patch does a bit more than that, as it also removes the saving
> of the registers from the suspend calls, which is most likely handled
> by the driver now. But the description should possibly reflect that.
True, although I couldn't test suspend/resume with these patches, because
it was already broken before, at least on s3c64xx and/or mini6410.
As an interesting side note, in case of s3c64xx and s5p64x0, existing code
was not enough to make suspend/resume of the timer work, as it can be seen
in case of s5pv210, which has it done almost correctly.
Almost, because as far as I know (and I can see in the manual) the TCNTO
register is read only and there is a separate procedure for loading timer
value manually.
Thanks for review.
Best regards,
Tomasz
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> > ---
> >
> > arch/arm/mach-s3c64xx/irq-pm.c | 2 --
> > arch/arm/mach-s5p64x0/pm.c | 3 ---
> > arch/arm/mach-s5pv210/pm.c | 10 ----------
> > arch/arm/plat-samsung/s5p-irq.c | 1 -
> > 4 files changed, 16 deletions(-)
> >
> > diff --git a/arch/arm/mach-s3c64xx/irq-pm.c
> > b/arch/arm/mach-s3c64xx/irq-pm.c index 0c7e1d9..c3da1b6 100644
> > --- a/arch/arm/mach-s3c64xx/irq-pm.c
> > +++ b/arch/arm/mach-s3c64xx/irq-pm.c
> > @@ -22,7 +22,6 @@
> >
> > #include <mach/map.h>
> >
> > #include <plat/regs-serial.h>
> >
> > -#include <plat/regs-timer.h>
> >
> > #include <mach/regs-gpio.h>
> > #include <plat/cpu.h>
> > #include <plat/pm.h>
> >
> > @@ -43,7 +42,6 @@ static struct sleep_save irq_save[] = {
> >
> > SAVE_ITEM(S3C64XX_EINT0FLTCON2),
> > SAVE_ITEM(S3C64XX_EINT0FLTCON3),
> > SAVE_ITEM(S3C64XX_EINT0MASK),
> >
> > - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> >
> > };
> >
> > static struct irq_grp_save {
> >
> > diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
> > index 97c2a08a..861e15c 100644
> > --- a/arch/arm/mach-s5p64x0/pm.c
> > +++ b/arch/arm/mach-s5p64x0/pm.c
> > @@ -18,7 +18,6 @@
> >
> > #include <plat/cpu.h>
> > #include <plat/pm.h>
> >
> > -#include <plat/regs-timer.h>
> >
> > #include <plat/wakeup-mask.h>
> >
> > #include <mach/regs-clock.h>
> >
> > @@ -48,8 +47,6 @@ static struct sleep_save s5p64x0_misc_save[] = {
> >
> > SAVE_ITEM(S5P64X0_MEM0CONSLP1),
> > SAVE_ITEM(S5P64X0_MEM0DRVCON),
> > SAVE_ITEM(S5P64X0_MEM1DRVCON),
> >
> > -
> > - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> >
> > };
> >
> > /* DPLL is present only in S5P6450 */
> >
> > diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
> > index 2b68a67..3cf3f9c 100644
> > --- a/arch/arm/mach-s5pv210/pm.c
> > +++ b/arch/arm/mach-s5pv210/pm.c
> > @@ -21,7 +21,6 @@
> >
> > #include <plat/cpu.h>
> > #include <plat/pm.h>
> >
> > -#include <plat/regs-timer.h>
> >
> > #include <mach/regs-irq.h>
> > #include <mach/regs-clock.h>
> >
> > @@ -77,15 +76,6 @@ static struct sleep_save s5pv210_core_save[] = {
> >
> > /* Clock ETC */
> > SAVE_ITEM(S5P_CLK_OUT),
> > SAVE_ITEM(S5P_MDNIE_SEL),
> >
> > -
> > - /* PWM Register */
> > - SAVE_ITEM(S3C2410_TCFG0),
> > - SAVE_ITEM(S3C2410_TCFG1),
> > - SAVE_ITEM(S3C64XX_TINT_CSTAT),
> > - SAVE_ITEM(S3C2410_TCON),
> > - SAVE_ITEM(S3C2410_TCNTB(0)),
> > - SAVE_ITEM(S3C2410_TCMPB(0)),
> > - SAVE_ITEM(S3C2410_TCNTO(0)),
> >
> > };
> >
> > static int s5pv210_cpu_suspend(unsigned long arg)
> >
> > diff --git a/arch/arm/plat-samsung/s5p-irq.c
> > b/arch/arm/plat-samsung/s5p-irq.c index 6729cb2..ddfaca9 100644
> > --- a/arch/arm/plat-samsung/s5p-irq.c
> > +++ b/arch/arm/plat-samsung/s5p-irq.c
> > @@ -17,7 +17,6 @@
> >
> > #include <mach/irqs.h>
> > #include <mach/map.h>
> >
> > -#include <plat/regs-timer.h>
> >
> > #include <plat/cpu.h>
> >
> > void __init s5p_init_irq(u32 *vic, u32 num_vic)
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-samsung-soc" in the body of a message to
> majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 00/15] Final Samsung PWM support cleanup
2013-06-13 20:17 ` Heiko Stübner
@ 2013-06-13 22:27 ` Heiko Stübner
0 siblings, 0 replies; 51+ messages in thread
From: Heiko Stübner @ 2013-06-13 22:27 UTC (permalink / raw)
To: linux-arm-kernel
Am Donnerstag, 13. Juni 2013, 22:17:43 schrieb Heiko St?bner:
> Am Donnerstag, 13. Juni 2013, 11:07:38 schrieb Tomasz Figa:
> > Hi Heiko, Sylwester,
> >
> > On Thursday 13 of June 2013 01:52:05 Sylwester Nawrocki wrote:
> > > On 06/13/2013 01:38 AM, Heiko St?bner wrote:
> > > > Am Donnerstag, 13. Juni 2013, 01:13:47 schrieb Tomasz Figa:
> > > >> Hi Olof,
> > > >>
> > > >> On Wednesday 12 of June 2013 16:00:23 Olof Johansson wrote:
> > > >>> On Wed, Jun 12, 2013 at 11:48:56PM +0200, Tomasz Figa wrote:
> > > >>>>> Needs testing on other platforms as I could only compile test for
> > > >>>>> them.
> > > >>>
> > > >>> How/who can help here? WHo has and still cares for other affected
> > > >>> platforms?
> > > >>>
> > > >>>>> 66 files changed, 627 insertions(+), 1580 deletions(-)
> > > >>
> > > >> I will try to test this on Exynos 4 at work, if I somehow manage to
> > > >> find any way to use PWM on our boards (other than already-tested PWM
> > > >> clocksource).
> > > >>
> > > >> Unfortunately, except S3C6410, I don't have access to other
> > > >> platforms, or at least I won't in any reasonable time.
> > > >>
> > > >> If I remember correctly, in case of my watchdog support cleanup,
> > > >> Kukjin
> > > >> has been able to test it on S5P64x0.
> > > >>
> > > >> Heiko and Sylwester used to have some s3c24xx-based boards, not sure
> > > >> if
> > > >> they still do and are interested in their support in mainline.
> > > >>
> > > >> So all left is S5PC100 (for which I couldn't find anyone who cares)
> > > >> and
> > > >> Exynos5.
> > > >>
> > > >>> Nice cleanup.
> > > >>
> > > >> Thanks.
> > > >>
> > > >>>> Any comments for this series?
> > > >>>
> > > >>> Yes, above. :) In general looks good -- testing coverage is a bit
> > > >>> of a
> > > >>> concern.
> > > >>
> > > >> Yeah. Unfortunately all I could do was testing on Tiny6410 and
> > > >> compile
> > > >> testing on others. I hope we find some really helpful people over
> > > >> here who could waste a bit of their precious time for this museum.
> > > >> ;)
> > > >
> > > > I'll try to give it a testrun tomorrow. And my s3c2416 will always be
> > > > the first-love-architecture for me ;-)
> > >
> > > I'll likely test it tomorrow on a Mini2440 board, I was going to do it
> > > earlier
> > > but got distracted by plenty other things that needed attention too. At
> > > least
> > > that's one of the reasons I got the board - testing the cross-platform
> > > cleanups
> > > and ensuring they are not breaking the older platforms.
> >
> > Thank you both for your support. Looking forward for testing results :)
>
> on a s3c2416-based machine for dt and non-dt case
> [with the limit that my machine does not has anything connected to the pwm
> outputs, so I only get to test the base-pwm and timer part]
>
> Tested-by: Heiko Stuebner <heiko@sntech.de>
And of course forgot the other thing:
Acked-by: Heiko Stuebner <heiko@sntech.de>
Thanks for doing this, as with this series I can now also resurrect my s3c2416
ccf patch :-)
Heiko
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
2013-06-13 20:14 ` Heiko Stübner
@ 2013-06-16 17:19 ` Tomasz Figa
2013-06-16 20:45 ` Kukjin Kim
2013-06-17 20:29 ` Thierry Reding
2 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-16 17:19 UTC (permalink / raw)
To: linux-arm-kernel
Hi Kukjin,
On Wednesday 05 of June 2013 23:18:13 Tomasz Figa wrote:
> This patch introduces new Samsung PWM driver, which uses Samsung
> PWM/timer master driver to control shared parts of the hardware.
>
> Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> ---
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-samsung.c | 528
> ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> insertions(+)
> create mode 100644 drivers/pwm/pwm-samsung.c
I you haven't yet merged this patch, please let me send v2 of this series,
addressing Heiko's comments and adjustments to my understanding of the PWM
hardware after getting access to SMDK6410 board, which uses PWM to control
LCD backlight.
Best regards,
Tomasz
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 229a599..833c3ac 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
> obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
> obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
> +obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> new file mode 100644
> index 0000000..61bed3d
> --- /dev/null
> +++ b/drivers/pwm/pwm-samsung.c
> @@ -0,0 +1,528 @@
> +/* drivers/pwm/pwm-samsung.c
> + *
> + * Copyright (c) 2007 Ben Dooks
> + * Copyright (c) 2008 Simtec Electronics
> + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> + *
> + * PWM driver 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 as published
> by + * the Free Software Foundation; either version 2 of the License.
> +*/
> +
> +#include <linux/clk.h>
> +#include <linux/export.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/time.h>
> +
> +#include <clocksource/samsung_pwm.h>
> +
> +#define REG_TCFG0 0x00
> +#define REG_TCFG1 0x04
> +#define REG_TCON 0x08
> +
> +#define REG_TCNTB(tmr) (0x0c + ((tmr) * 0xc))
> +#define REG_TCMPB(tmr) (0x10 + ((tmr) * 0xc))
> +
> +#define TCFG0_PRESCALER_MASK 0xff
> +#define TCFG0_PRESCALER1_SHIFT 8
> +
> +#define TCFG1_MUX_MASK 0xf
> +#define TCFG1_SHIFT(x) ((x) * 4)
> +
> +#define TCON_START(chan) (1 << (4 * (chan) + 0))
> +#define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1))
> +#define TCON_INVERT(chan) (1 << (4 * (chan) + 2))
> +#define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3))
> +
> +struct samsung_pwm_channel {
> + unsigned long period_ns;
> + unsigned long duty_ns;
> + unsigned long tin_ns;
> +};
> +
> +struct samsung_pwm_chip {
> + struct pwm_chip chip;
> + struct samsung_pwm_variant variant;
> + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
> +
> + void __iomem *base;
> + struct clk *base_clk;
> + struct clk *tclk0;
> + struct clk *tclk1;
> +};
> +#define to_samsung_pwm_chip(chip) \
> + container_of(chip, struct samsung_pwm_chip, chip)
> +
> +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> +static DEFINE_SPINLOCK(samsung_pwm_lock);
> +#endif
> +
> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> + unsigned int channel, u8 divisor)
> +{
> + u8 shift = TCFG1_SHIFT(channel);
> + unsigned long flags;
> + u32 reg;
> + u8 bits;
> +
> + bits = (fls(divisor) - 1) - pwm->variant.div_base;
> +
> + spin_lock_irqsave(&samsung_pwm_lock, flags);
> +
> + reg = readl(pwm->base + REG_TCFG1);
> + reg &= ~(TCFG1_MUX_MASK << shift);
> + reg |= bits << shift;
> + writel(reg, pwm->base + REG_TCFG1);
> +
> + spin_unlock_irqrestore(&samsung_pwm_lock, flags);
> +}
> +
> +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
> + unsigned int chan)
> +{
> + struct samsung_pwm_variant *variant = &chip->variant;
> + u32 reg;
> +
> + reg = readl(chip->base + REG_TCFG1);
> + reg >>= TCFG1_SHIFT(chan);
> + reg &= TCFG1_MUX_MASK;
> +
> + return ((1 << reg) & variant->tclk_mask) == 0;
> +}
> +
> +static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip
> *chip, + unsigned
int chan)
> +{
> + unsigned long rate;
> + u32 reg;
> +
> + rate = clk_get_rate(chip->base_clk);
> +
> + reg = readl(chip->base + REG_TCFG0);
> + if (chan >= 2)
> + reg >>= TCFG0_PRESCALER1_SHIFT;
> + reg &= TCFG0_PRESCALER_MASK;
> +
> + return rate / (reg + 1);
> +}
> +
> +static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip
> *chip, + unsigned int chan,
unsigned long freq)
> +{
> + struct samsung_pwm_variant *variant = &chip->variant;
> + unsigned long rate;
> + unsigned int div;
> + struct clk *clk;
> +
> + if (!pwm_samsung_is_tdiv(chip, chan)) {
> + clk = (chan < 2) ? chip->tclk0 : chip->tclk1;
> + if (!IS_ERR(clk)) {
> + rate = clk_get_rate(clk);
> + if (rate)
> + return rate;
> + }
> +
> + dev_warn(chip->chip.dev,
> + "tclk of PWM %d is inoperational, using tdiv\n",
chan);
> + }
> +
> + rate = pwm_samsung_get_tin_rate(chip, chan);
> + dev_dbg(chip->chip.dev, "tin parent at %lu\n", rate);
> +
> + /*
> + * Compare minimum PWM frequency that can be achieved with
possible
> + * divider settings and choose the lowest divisor that can
generate
> + * frequencies lower than requested.
> + */
> + for (div = variant->div_base; div < 4; ++div)
> + if ((rate >> (variant->bits + div)) < freq)
> + break;
> +
> + pwm_samsung_set_divisor(chip, chan, 1 << div);
> +
> + return rate >> div;
> +}
> +
> +static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device
> *pwm) +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> +
> + if (our_chip->variant.output_mask & (1 << pwm->hwpwm))
> + return 0;
> +
> + dev_warn(our_chip->chip.dev,
> + "tried to request PWM channel %d without
output\n",
> + pwm->hwpwm);
> +
> + return -EINVAL;
> +}
> +
> +static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device
> *pwm) +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + unsigned int channel = pwm->hwpwm;
> + unsigned long tcon;
> + unsigned long flags;
> +
> + if (channel > 0)
> + ++channel;
> +
> + spin_lock_irqsave(&samsung_pwm_lock, flags);
> +
> + tcon = __raw_readl(our_chip->base + REG_TCON);
> +
> + tcon &= ~TCON_MANUALUPDATE(channel);
> + tcon |= TCON_START(channel) | TCON_AUTORELOAD(channel);
> +
> + __raw_writel(tcon, our_chip->base + REG_TCON);
> +
> + spin_unlock_irqrestore(&samsung_pwm_lock, flags);
> +
> + return 0;
> +}
> +
> +static void pwm_samsung_disable(struct pwm_chip *chip, struct
> pwm_device *pwm) +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + unsigned int channel = pwm->hwpwm;
> + unsigned long tcon;
> + unsigned long flags;
> +
> + if (channel > 0)
> + ++channel;
> +
> + spin_lock_irqsave(&samsung_pwm_lock, flags);
> +
> + tcon = __raw_readl(our_chip->base + REG_TCON);
> + tcon &= ~TCON_AUTORELOAD(channel);
> + __raw_writel(tcon, our_chip->base + REG_TCON);
> +
> + spin_unlock_irqrestore(&samsung_pwm_lock, flags);
> +}
> +
> +static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device
> *pwm, + int duty_ns, int period_ns)
> +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + struct samsung_pwm_channel *chan = &our_chip->channels[pwm-
>hwpwm];
> + unsigned long tin_ns = chan->tin_ns;
> + unsigned int tcon_chan = pwm->hwpwm;
> + unsigned long tin_rate;
> + unsigned long period;
> + unsigned long flags;
> + unsigned long tcnt;
> + long tcmp;
> + u32 tcon;
> +
> + /* We currently avoid using 64bit arithmetic by using the
> + * fact that anything faster than 1Hz is easily representable
> + * by 32bits. */
> + if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> + return -ERANGE;
> +
> + if (period_ns == chan->period_ns && duty_ns == chan->duty_ns)
> + return 0;
> +
> + /* The TCMP and TCNT can be read without a lock, they're not
> + * shared between the timers. */
> + tcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm));
> + tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
> +
> + period = NSEC_PER_SEC / period_ns;
> +
> + dev_dbg(our_chip->chip.dev, "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 (chan->period_ns != period_ns) {
> + tin_rate = pwm_samsung_calc_tin(our_chip, pwm->hwpwm,
period);
> +
> + chan->period_ns = period_ns;
> +
> + dev_dbg(our_chip->chip.dev, "tin_rate=%lu\n", tin_rate);
> +
> + tin_ns = NSEC_PER_SEC / tin_rate;
> + tcnt = period_ns / tin_ns;
> +
> + chan->tin_ns = tin_ns;
> + }
> +
> + /* Note, counters count down */
> + tcmp = duty_ns / tin_ns;
> + tcmp = tcnt - tcmp;
> +
> + /* the pwm hw only checks the compare register after a decrement,
> + so the pin never toggles if tcmp = tcnt */
> + if (tcmp == tcnt)
> + tcmp--;
> +
> + dev_dbg(our_chip->chip.dev, "tin_ns=%lu, tcmp=%ld/%lu\n",
> + tin_ns, tcmp,
tcnt);
> +
> + if (tcmp < 0)
> + tcmp = 0;
> +
> + /* Update the PWM register block. */
> + if (tcon_chan > 0)
> + ++tcon_chan;
> +
> + spin_lock_irqsave(&samsung_pwm_lock, flags);
> +
> + tcon = __raw_readl(our_chip->base + REG_TCON);
> +
> + tcnt--;
> +
> + tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan));
> + tcon |= TCON_MANUALUPDATE(tcon_chan);
> +
> + __raw_writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
> + __raw_writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
> + __raw_writel(tcon, our_chip->base + REG_TCON);
> +
> + spin_unlock_irqrestore(&samsung_pwm_lock, flags);
> +
> + return 0;
> +}
> +
> +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> + struct pwm_device *pwm, enum pwm_polarity
polarity)
> +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + unsigned int channel = pwm->hwpwm;
> + unsigned long flags;
> + u32 tcon;
> +
> + if (channel > 0)
> + ++channel;
> +
> + spin_lock_irqsave(&samsung_pwm_lock, flags);
> +
> + tcon = __raw_readl(our_chip->base + REG_TCON);
> +
> + /* Invert in hardware means normal polarity of PWM core */
> + if (polarity == PWM_POLARITY_NORMAL)
> + tcon |= TCON_INVERT(channel);
> + else
> + tcon &= ~TCON_INVERT(channel);
> +
> + __raw_writel(tcon, our_chip->base + REG_TCON);
> +
> + spin_unlock_irqrestore(&samsung_pwm_lock, flags);
> +
> + return 0;
> +}
> +
> +static struct pwm_ops pwm_samsung_ops = {
> + .request = pwm_samsung_request,
> + .enable = pwm_samsung_enable,
> + .disable = pwm_samsung_disable,
> + .config = pwm_samsung_config,
> + .set_polarity = pwm_samsung_set_polarity,
> + .owner = THIS_MODULE,
> +};
> +
> +#ifdef CONFIG_OF
> +static const struct samsung_pwm_variant s3c24xx_variant = {
> + .bits = 16,
> + .div_base = 1,
> + .has_tint_cstat = false,
> + .tclk_mask = (1 << 4),
> +};
> +
> +static const struct samsung_pwm_variant s3c64xx_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
> +};
> +
> +static const struct samsung_pwm_variant s5p64x0_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = 0,
> +};
> +
> +static const struct samsung_pwm_variant s5p_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = (1 << 5),
> +};
> +
> +static const struct of_device_id samsung_pwm_matches[] = {
> + { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> + { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> + { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> + { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> + { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant
},
> + {},
> +};
> +#endif
> +
> +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> +{
> + struct device_node *np = chip->chip.dev->of_node;
> + const struct of_device_id *match;
> + struct property *prop;
> + const __be32 *cur;
> + u32 val;
> +
> + match = of_match_node(samsung_pwm_matches, np);
> + if (!match)
> + return -ENODEV;
> +
> + memcpy(&chip->variant, match->data, sizeof(chip->variant));
> +
> + of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur,
val) {
> + if (val >= SAMSUNG_PWM_NUM) {
> + pr_warning("%s: invalid channel index in
samsung,pwm-outputs
> property\n", +
__func__);
> + continue;
> + }
> + chip->variant.output_mask |= 1 << val;
> + }
> +
> + return 0;
> +}
> +
> +static int pwm_samsung_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct samsung_pwm_chip *chip;
> + struct resource *res;
> + int ret;
> +
> + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> + if (chip == NULL) {
> + dev_err(dev, "failed to allocate driver data\n");
> + return -ENOMEM;
> + }
> +
> + chip->chip.dev = &pdev->dev;
> + chip->chip.ops = &pwm_samsung_ops;
> + chip->chip.base = -1;
> + chip->chip.npwm = SAMSUNG_PWM_NUM;
> +
> + if (pdev->dev.of_node) {
> + ret = pwm_samsung_parse_dt(chip);
> + if (ret)
> + return ret;
> +
> + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> + chip->chip.of_pwm_n_cells = 3;
> + } else {
> + if (!pdev->dev.platform_data) {
> + dev_err(&pdev->dev, "no platform data
specified\n");
> + return -EINVAL;
> + }
> +
> + memcpy(&chip->variant, pdev->dev.platform_data,
> + sizeof(chip-
>variant));
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get mem resource\n");
> + return -ENOMEM;
> + }
> +
> + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> + if (!chip->base) {
> + dev_err(&pdev->dev, "failed to request and map
registers\n");
> + return -ENOMEM;
> + }
> +
> + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> + if (IS_ERR(chip->base_clk)) {
> + dev_err(dev, "failed to get timer base clk\n");
> + return PTR_ERR(chip->base_clk);
> + }
> + clk_prepare_enable(chip->base_clk);
> +
> + chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
> + chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
> +
> + ret = pwmchip_add(&chip->chip);
> + if (ret < 0) {
> + dev_err(dev, "failed to register pwm\n");
> + goto err_clk_disable;
> + }
> +
> + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> + clk_get_rate(chip->base_clk),
> + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> +
> + platform_set_drvdata(pdev, chip);
> +
> + return 0;
> +
> +err_clk_disable:
> + clk_disable_unprepare(chip->base_clk);
> +
> + return ret;
> +}
> +
> +static int pwm_samsung_remove(struct platform_device *pdev)
> +{
> + struct samsung_pwm_chip *chip = platform_get_drvdata(pdev);
> + int err;
> +
> + err = pwmchip_remove(&chip->chip);
> + if (err < 0)
> + return err;
> +
> + clk_disable_unprepare(chip->base_clk);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int pwm_samsung_suspend(struct device *dev)
> +{
> + struct samsung_pwm_chip *chip = dev_get_drvdata(dev);
> + int i;
> +
> + /* No one preserve these values during suspend so reset them
> + * Otherwise driver leaves PWM unconfigured if same values
> + * passed to pwm_config
> + */
> + for (i = 0; i < SAMSUNG_PWM_NUM; ++i) {
> + chip->channels[i].period_ns = 0;
> + chip->channels[i].duty_ns = 0;
> + }
> +
> + return 0;
> +}
> +#endif
> +
> +static struct dev_pm_ops pwm_samsung_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pwm_samsung_suspend, NULL)
> +};
> +
> +static struct platform_driver pwm_samsung_driver = {
> + .driver = {
> + .name = "samsung-pwm",
> + .owner = THIS_MODULE,
> + .pm = &pwm_samsung_pm_ops,
> + .of_match_table = of_match_ptr(samsung_pwm_matches),
> + },
> + .probe = pwm_samsung_probe,
> + .remove = pwm_samsung_remove,
> +};
> +module_platform_driver(pwm_samsung_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
> +MODULE_ALIAS("platform:samsung-pwm");
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-16 17:19 ` Tomasz Figa
@ 2013-06-16 20:45 ` Kukjin Kim
0 siblings, 0 replies; 51+ messages in thread
From: Kukjin Kim @ 2013-06-16 20:45 UTC (permalink / raw)
To: linux-arm-kernel
On 06/17/13 02:19, Tomasz Figa wrote:
> Hi Kukjin,
>
> On Wednesday 05 of June 2013 23:18:13 Tomasz Figa wrote:
>> This patch introduces new Samsung PWM driver, which uses Samsung
>> PWM/timer master driver to control shared parts of the hardware.
>>
>> Signed-off-by: Tomasz Figa<tomasz.figa@gmail.com>
>> ---
>> drivers/pwm/Makefile | 1 +
>> drivers/pwm/pwm-samsung.c | 528
>> ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
>> insertions(+)
>> create mode 100644 drivers/pwm/pwm-samsung.c
>
> I you haven't yet merged this patch, please let me send v2 of this series,
> addressing Heiko's comments and adjustments to my understanding of the PWM
> hardware after getting access to SMDK6410 board, which uses PWM to control
> LCD backlight.
>
Sure, let me hold on until getting your updated series.
Thanks,
- Kukjin
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
2013-06-13 20:14 ` Heiko Stübner
2013-06-16 17:19 ` Tomasz Figa
@ 2013-06-17 20:29 ` Thierry Reding
2013-06-17 20:50 ` Tomasz Figa
` (2 more replies)
2 siblings, 3 replies; 51+ messages in thread
From: Thierry Reding @ 2013-06-17 20:29 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> This patch introduces new Samsung PWM driver, which uses Samsung
> PWM/timer master driver to control shared parts of the hardware.
>
> Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
Sorry for jumping in so late, I've been busy with other things lately.
> ---
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-samsung.c | 528 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 529 insertions(+)
> create mode 100644 drivers/pwm/pwm-samsung.c
>
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 229a599..833c3ac 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
> obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
> obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
> +obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> new file mode 100644
> index 0000000..61bed3d
> --- /dev/null
> +++ b/drivers/pwm/pwm-samsung.c
> @@ -0,0 +1,528 @@
> +/* drivers/pwm/pwm-samsung.c
Nit: this line can be dropped. It serves no purpose.
> + *
> + * Copyright (c) 2007 Ben Dooks
> + * Copyright (c) 2008 Simtec Electronics
> + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> + *
> + * PWM driver 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 as published by
> + * the Free Software Foundation; either version 2 of the License.
> +*/
Nit: the */ should align with the * above.
> +struct samsung_pwm_channel {
> + unsigned long period_ns;
> + unsigned long duty_ns;
> + unsigned long tin_ns;
> +};
> +
> +struct samsung_pwm_chip {
> + struct pwm_chip chip;
> + struct samsung_pwm_variant variant;
> + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
The new driver for Renesas did something similar, but I want to
discourage storing per-channel data within the chip structure.
The PWM framework provides a way to store this information along with
the PWM device (see pwm_{set,get}_chip_data()).
> +
> + void __iomem *base;
> + struct clk *base_clk;
> + struct clk *tclk0;
> + struct clk *tclk1;
> +};
> +#define to_samsung_pwm_chip(chip) \
> + container_of(chip, struct samsung_pwm_chip, chip)
Can you turn this into a static inline function please?
> +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> +static DEFINE_SPINLOCK(samsung_pwm_lock);
> +#endif
Why is this lock global? Shouldn't it more correctly be part of
samsung_pwm_chip?
> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> + unsigned int channel, u8 divisor)
Nit: please align arguments on subsequent lines with the first argument
of the first line. There's many more of these but I haven't mentioned
them all explicitly.
> +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
Any particular reason for making this inline?
> +static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
> + int duty_ns, int period_ns)
> +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + struct samsung_pwm_channel *chan = &our_chip->channels[pwm->hwpwm];
> + unsigned long tin_ns = chan->tin_ns;
> + unsigned int tcon_chan = pwm->hwpwm;
> + unsigned long tin_rate;
> + unsigned long period;
> + unsigned long flags;
> + unsigned long tcnt;
Many of these unsigned long variable could be declared on a single line
to make the function shorter.
> + long tcmp;
> + u32 tcon;
> +
> + /* We currently avoid using 64bit arithmetic by using the
> + * fact that anything faster than 1Hz is easily representable
> + * by 32bits. */
Can you turn these into proper block-style comments? Like so:
/*
* We currently...
* ...
* by 32 bits.
*/
> + if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> + return -ERANGE;
Note that technically you only need to check period_ns because the core
already ensures that duty_ns <= period_ns.
> +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> + struct pwm_device *pwm, enum pwm_polarity polarity)
> +{
> + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> + unsigned int channel = pwm->hwpwm;
> + unsigned long flags;
> + u32 tcon;
> +
> + if (channel > 0)
> + ++channel;
You have to repeat that in quite a few places, so I wonder if it'd make
sense to wrap it into a function and add a comment about why the
increment is necessary.
> +static struct pwm_ops pwm_samsung_ops = {
"static const" please.
> +#ifdef CONFIG_OF
> +static const struct samsung_pwm_variant s3c24xx_variant = {
> + .bits = 16,
> + .div_base = 1,
> + .has_tint_cstat = false,
> + .tclk_mask = (1 << 4),
> +};
> +
> +static const struct samsung_pwm_variant s3c64xx_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
> +};
> +
> +static const struct samsung_pwm_variant s5p64x0_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = 0,
> +};
> +
> +static const struct samsung_pwm_variant s5p_variant = {
> + .bits = 32,
> + .div_base = 0,
> + .has_tint_cstat = true,
> + .tclk_mask = (1 << 5),
> +};
> +
> +static const struct of_device_id samsung_pwm_matches[] = {
> + { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> + { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> + { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> + { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> + { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant },
> + {},
> +};
> +#endif
> +
> +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> +{
> + struct device_node *np = chip->chip.dev->of_node;
> + const struct of_device_id *match;
> + struct property *prop;
> + const __be32 *cur;
> + u32 val;
> +
> + match = of_match_node(samsung_pwm_matches, np);
> + if (!match)
> + return -ENODEV;
> +
> + memcpy(&chip->variant, match->data, sizeof(chip->variant));
> +
> + of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
> + if (val >= SAMSUNG_PWM_NUM) {
> + pr_warning("%s: invalid channel index in samsung,pwm-outputs property\n",
> + __func__);
> + continue;
> + }
> + chip->variant.output_mask |= 1 << val;
Could the output_mask be moved to the struct samsung_pwm_chip instead?
The reason I ask is because it would allow you to make the variant
constant throughout the driver.
> +static int pwm_samsung_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct samsung_pwm_chip *chip;
> + struct resource *res;
> + int ret;
> +
> + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> + if (chip == NULL) {
> + dev_err(dev, "failed to allocate driver data\n");
> + return -ENOMEM;
> + }
> +
> + chip->chip.dev = &pdev->dev;
> + chip->chip.ops = &pwm_samsung_ops;
> + chip->chip.base = -1;
> + chip->chip.npwm = SAMSUNG_PWM_NUM;
> +
> + if (pdev->dev.of_node) {
Maybe add an IS_ENABLED(CONFIG_OF) check here? That'd allow all OF-
related code to be thrown away if OF isn't selected.
> + ret = pwm_samsung_parse_dt(chip);
> + if (ret)
> + return ret;
> +
> + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> + chip->chip.of_pwm_n_cells = 3;
> + } else {
> + if (!pdev->dev.platform_data) {
> + dev_err(&pdev->dev, "no platform data specified\n");
> + return -EINVAL;
> + }
> +
> + memcpy(&chip->variant, pdev->dev.platform_data,
> + sizeof(chip->variant));
> + }
Obviously this needs some modification in order for the variant to
become constant. But I think you can easily do so by making the driver
match using the platform_driver's id_table field, similar to how the
matching is done for OF.
> + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> + if (!chip->base) {
> + dev_err(&pdev->dev, "failed to request and map registers\n");
> + return -ENOMEM;
> + }
devm_request_and_ioremap() is now deprecated and in the process of being
removed. You should use devm_ioremap_resource() instead.
> +
> + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> + if (IS_ERR(chip->base_clk)) {
> + dev_err(dev, "failed to get timer base clk\n");
> + return PTR_ERR(chip->base_clk);
> + }
> + clk_prepare_enable(chip->base_clk);
You need to check the return value of clk_prepare_enable(). And if I was
very pedantic, there should be a blank line before this one.
> + ret = pwmchip_add(&chip->chip);
> + if (ret < 0) {
> + dev_err(dev, "failed to register pwm\n");
"failed to register PWM chip" please.
> + goto err_clk_disable;
> + }
> +
> + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> + clk_get_rate(chip->base_clk),
> + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> +
> + platform_set_drvdata(pdev, chip);
> +
> + return 0;
> +
> +err_clk_disable:
> + clk_disable_unprepare(chip->base_clk);
> +
> + return ret;
There's only a single case where this can actually happen, so I don't
think you need the label here. Just put the clk_disable_unprepare() call
and the return statement where you jump to the label.
> +#ifdef CONFIG_PM
I think this should really be CONFIG_PM_SLEEP.
> +static struct dev_pm_ops pwm_samsung_pm_ops = {
"static const" please.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130617/f10d2c6e/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-17 20:29 ` Thierry Reding
@ 2013-06-17 20:50 ` Tomasz Figa
2013-06-18 22:17 ` Thierry Reding
2013-06-18 17:59 ` Tomasz Figa
2013-06-18 19:41 ` Tomasz Figa
2 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-17 20:50 UTC (permalink / raw)
To: linux-arm-kernel
Hi Thierry,
On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > This patch introduces new Samsung PWM driver, which uses Samsung
> > PWM/timer master driver to control shared parts of the hardware.
> >
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
>
> Sorry for jumping in so late, I've been busy with other things lately.
>
> > ---
> >
> > drivers/pwm/Makefile | 1 +
> > drivers/pwm/pwm-samsung.c | 528
> > ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> > insertions(+)
> > create mode 100644 drivers/pwm/pwm-samsung.c
> >
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 229a599..833c3ac 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
> >
> > obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
> > obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
> >
> > +obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> >
> > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> > obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> > obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> >
> > diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> > new file mode 100644
> > index 0000000..61bed3d
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-samsung.c
> > @@ -0,0 +1,528 @@
> > +/* drivers/pwm/pwm-samsung.c
>
> Nit: this line can be dropped. It serves no purpose.
OK.
> > + *
> > + * Copyright (c) 2007 Ben Dooks
> > + * Copyright (c) 2008 Simtec Electronics
> > + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> > + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> > + *
> > + * PWM driver 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 as
> > published by + * the Free Software Foundation; either version 2 of
> > the License. +*/
>
> Nit: the */ should align with the * above.
OK.
> > +struct samsung_pwm_channel {
> > + unsigned long period_ns;
> > + unsigned long duty_ns;
> > + unsigned long tin_ns;
> > +};
> > +
> > +struct samsung_pwm_chip {
> > + struct pwm_chip chip;
> > + struct samsung_pwm_variant variant;
> > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
>
> The new driver for Renesas did something similar, but I want to
> discourage storing per-channel data within the chip structure.
>
> The PWM framework provides a way to store this information along with
> the PWM device (see pwm_{set,get}_chip_data()).
OK, this should be better indeed.
> > +
> > + void __iomem *base;
> > + struct clk *base_clk;
> > + struct clk *tclk0;
> > + struct clk *tclk1;
> > +};
> > +#define to_samsung_pwm_chip(chip) \
> > + container_of(chip, struct samsung_pwm_chip, chip)
>
> Can you turn this into a static inline function please?
OK.
> > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > +#endif
>
> Why is this lock global? Shouldn't it more correctly be part of
> samsung_pwm_chip?
There are few registers shared with samsung_pwm_timer clocksource driver
and so normally the spinlock is exported from it. However on on some
platforms (namely Exynos >=4x12) kernel can be compiled without that
driver, so the lock must be defined locally, just to synchronize multiple
PWM channels, as they share registers as well.
> > +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > + unsigned int channel, u8 divisor)
>
> Nit: please align arguments on subsequent lines with the first argument
> of the first line. There's many more of these but I haven't mentioned
> them all explicitly.
OK.
> > +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
>
> Any particular reason for making this inline?
Nope. Fixed in v2 that I'm going to send soon.
> > +static int pwm_samsung_config(struct pwm_chip *chip, struct
> > pwm_device *pwm, + int duty_ns, int period_ns)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + struct samsung_pwm_channel *chan = &our_chip->channels[pwm-
>hwpwm];
> > + unsigned long tin_ns = chan->tin_ns;
> > + unsigned int tcon_chan = pwm->hwpwm;
> > + unsigned long tin_rate;
> > + unsigned long period;
> > + unsigned long flags;
> > + unsigned long tcnt;
>
> Many of these unsigned long variable could be declared on a single line
> to make the function shorter.
OK. I have almost completely reworked this function in v2 and it needs
just 5 variables here.
> > + long tcmp;
> > + u32 tcon;
> > +
> > + /* We currently avoid using 64bit arithmetic by using the
> > + * fact that anything faster than 1Hz is easily representable
> > + * by 32bits. */
>
> Can you turn these into proper block-style comments? Like so:
Sure.
> /*
> * We currently...
> * ...
> * by 32 bits.
> */
>
> > + if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> > + return -ERANGE;
>
> Note that technically you only need to check period_ns because the core
> already ensures that duty_ns <= period_ns.
OK.
> > +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> > + struct pwm_device *pwm, enum pwm_polarity
polarity)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + unsigned int channel = pwm->hwpwm;
> > + unsigned long flags;
> > + u32 tcon;
> > +
> > + if (channel > 0)
> > + ++channel;
>
> You have to repeat that in quite a few places, so I wonder if it'd make
> sense to wrap it into a function and add a comment about why the
> increment is necessary.
Hmm, might make sense to put this into a function indeed. Basically this
is a trick to work around broken bit layout in TCON register.
> > +static struct pwm_ops pwm_samsung_ops = {
>
> "static const" please.
>
OK.
> > +#ifdef CONFIG_OF
> > +static const struct samsung_pwm_variant s3c24xx_variant = {
> > + .bits = 16,
> > + .div_base = 1,
> > + .has_tint_cstat = false,
> > + .tclk_mask = (1 << 4),
> > +};
> > +
> > +static const struct samsung_pwm_variant s3c64xx_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p64x0_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = 0,
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 5),
> > +};
> > +
> > +static const struct of_device_id samsung_pwm_matches[] = {
> > + { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> > + { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> > + { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> > + { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> > + { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant
> > },
> > + {},
> > +};
> > +#endif
> > +
> > +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> > +{
> > + struct device_node *np = chip->chip.dev->of_node;
> > + const struct of_device_id *match;
> > + struct property *prop;
> > + const __be32 *cur;
> > + u32 val;
> > +
> > + match = of_match_node(samsung_pwm_matches, np);
> > + if (!match)
> > + return -ENODEV;
> > +
> > + memcpy(&chip->variant, match->data, sizeof(chip->variant));
> > +
> > + of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur,
val)
> > {
> > + if (val >= SAMSUNG_PWM_NUM) {
> > + pr_warning("%s: invalid channel index in
samsung,pwm-outputs
> > property\n", +
__func__);
> > + continue;
> > + }
> > + chip->variant.output_mask |= 1 << val;
>
> Could the output_mask be moved to the struct samsung_pwm_chip instead?
> The reason I ask is because it would allow you to make the variant
> constant throughout the driver.
Let me see what I can do about it.
> > +static int pwm_samsung_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct samsung_pwm_chip *chip;
> > + struct resource *res;
> > + int ret;
> > +
> > + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> > + if (chip == NULL) {
> > + dev_err(dev, "failed to allocate driver data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->chip.dev = &pdev->dev;
> > + chip->chip.ops = &pwm_samsung_ops;
> > + chip->chip.base = -1;
> > + chip->chip.npwm = SAMSUNG_PWM_NUM;
> > +
> > + if (pdev->dev.of_node) {
>
> Maybe add an IS_ENABLED(CONFIG_OF) check here? That'd allow all OF-
> related code to be thrown away if OF isn't selected.
OK.
> > + ret = pwm_samsung_parse_dt(chip);
> > + if (ret)
> > + return ret;
> > +
> > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > + chip->chip.of_pwm_n_cells = 3;
> > + } else {
> > + if (!pdev->dev.platform_data) {
> > + dev_err(&pdev->dev, "no platform data
specified\n");
> > + return -EINVAL;
> > + }
> > +
> > + memcpy(&chip->variant, pdev->dev.platform_data,
> > + sizeof(chip-
>variant));
> > + }
>
> Obviously this needs some modification in order for the variant to
> become constant. But I think you can easily do so by making the driver
> match using the platform_driver's id_table field, similar to how the
> matching is done for OF.
Generally output_mask is board-dependent and is passed inside a variant
struct using platform_data pointer.
Same platform data is used in samsung_pwm_timer clocksource driver, so I
just reused it here without adding the need to rename platform device at
runtime (see arch/arm/plat-samsung/devs.c).
> > + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> > + if (!chip->base) {
> > + dev_err(&pdev->dev, "failed to request and map
registers\n");
> > + return -ENOMEM;
> > + }
>
> devm_request_and_ioremap() is now deprecated and in the process of being
> removed. You should use devm_ioremap_resource() instead.
OK.
> > +
> > + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> > + if (IS_ERR(chip->base_clk)) {
> > + dev_err(dev, "failed to get timer base clk\n");
> > + return PTR_ERR(chip->base_clk);
> > + }
> > + clk_prepare_enable(chip->base_clk);
>
> You need to check the return value of clk_prepare_enable(). And if I was
> very pedantic, there should be a blank line before this one.
OK.
> > + ret = pwmchip_add(&chip->chip);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to register pwm\n");
>
> "failed to register PWM chip" please.
OK.
> > + goto err_clk_disable;
> > + }
> > +
> > + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> > + clk_get_rate(chip->base_clk),
> > + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> > + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> > +
> > + platform_set_drvdata(pdev, chip);
> > +
> > + return 0;
> > +
> > +err_clk_disable:
> > + clk_disable_unprepare(chip->base_clk);
> > +
> > + return ret;
>
> There's only a single case where this can actually happen, so I don't
> think you need the label here. Just put the clk_disable_unprepare() call
> and the return statement where you jump to the label.
Right. There were more labels here before and it made sense then, but now
it really doesn't make any indeed.
> > +#ifdef CONFIG_PM
>
> I think this should really be CONFIG_PM_SLEEP.
Right.
> > +static struct dev_pm_ops pwm_samsung_pm_ops = {
>
> "static const" please.
OK.
Thanks for your review.
Generally this driver suffers from too many leftovers from old one that I
was too lazy to completely rewrite. I have already fixed some of the
issues you mentioned in v2 that I have in the works, but I will address
rest of them as well.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-17 20:29 ` Thierry Reding
2013-06-17 20:50 ` Tomasz Figa
@ 2013-06-18 17:59 ` Tomasz Figa
2013-06-18 18:06 ` Kukjin Kim
2013-06-18 19:41 ` Tomasz Figa
2 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 17:59 UTC (permalink / raw)
To: linux-arm-kernel
Hi Thierry,
On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > This patch introduces new Samsung PWM driver, which uses Samsung
> > PWM/timer master driver to control shared parts of the hardware.
> >
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
>
> Sorry for jumping in so late, I've been busy with other things lately.
>
> > ---
> >
> > drivers/pwm/Makefile | 1 +
> > drivers/pwm/pwm-samsung.c | 528
> > ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> > insertions(+)
> > create mode 100644 drivers/pwm/pwm-samsung.c
> >
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 229a599..833c3ac 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
> >
> > obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
> > obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
> >
> > +obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> >
> > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> > obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> > obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> >
> > diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> > new file mode 100644
> > index 0000000..61bed3d
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-samsung.c
> > @@ -0,0 +1,528 @@
> > +/* drivers/pwm/pwm-samsung.c
>
> Nit: this line can be dropped. It serves no purpose.
>
> > + *
> > + * Copyright (c) 2007 Ben Dooks
> > + * Copyright (c) 2008 Simtec Electronics
> > + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> > + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> > + *
> > + * PWM driver 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 as
> > published by + * the Free Software Foundation; either version 2 of
> > the License. +*/
>
> Nit: the */ should align with the * above.
>
> > +struct samsung_pwm_channel {
> > + unsigned long period_ns;
> > + unsigned long duty_ns;
> > + unsigned long tin_ns;
> > +};
> > +
> > +struct samsung_pwm_chip {
> > + struct pwm_chip chip;
> > + struct samsung_pwm_variant variant;
> > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
>
> The new driver for Renesas did something similar, but I want to
> discourage storing per-channel data within the chip structure.
>
> The PWM framework provides a way to store this information along with
> the PWM device (see pwm_{set,get}_chip_data()).
>
> > +
> > + void __iomem *base;
> > + struct clk *base_clk;
> > + struct clk *tclk0;
> > + struct clk *tclk1;
> > +};
> > +#define to_samsung_pwm_chip(chip) \
> > + container_of(chip, struct samsung_pwm_chip, chip)
>
> Can you turn this into a static inline function please?
>
> > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > +#endif
>
> Why is this lock global? Shouldn't it more correctly be part of
> samsung_pwm_chip?
>
> > +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > + unsigned int channel, u8 divisor)
>
> Nit: please align arguments on subsequent lines with the first argument
> of the first line. There's many more of these but I haven't mentioned
> them all explicitly.
Hmm, I'm addressing all your comments that aren't addressed yet in v2 at
the moment and I'm wondering if this is really the correct way of breaking
function headers...
According to Documentation/CodingStyle:
/* Quotation starts */
Statements longer than 80 columns will be broken into sensible chunks,
unless exceeding 80 columns significantly increases readability and does
not hide information. Descendants are always substantially shorter than
the parent and are placed substantially to the right. The same applies to
function headers with a long argument list. However, never break user-
visible strings such as printk messages, because that breaks the ability
to grep for them.
/* Quotation ends */
Do I understand this incorrectly or does the above fragment state that
broken lines must be aligned to the right?
Best regards,
Tomasz
> > +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
>
> Any particular reason for making this inline?
>
> > +static int pwm_samsung_config(struct pwm_chip *chip, struct
> > pwm_device *pwm, + int duty_ns, int period_ns)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + struct samsung_pwm_channel *chan = &our_chip->channels[pwm-
>hwpwm];
> > + unsigned long tin_ns = chan->tin_ns;
> > + unsigned int tcon_chan = pwm->hwpwm;
> > + unsigned long tin_rate;
> > + unsigned long period;
> > + unsigned long flags;
> > + unsigned long tcnt;
>
> Many of these unsigned long variable could be declared on a single line
> to make the function shorter.
>
> > + long tcmp;
> > + u32 tcon;
> > +
> > + /* We currently avoid using 64bit arithmetic by using the
> > + * fact that anything faster than 1Hz is easily representable
> > + * by 32bits. */
>
> Can you turn these into proper block-style comments? Like so:
>
> /*
> * We currently...
> * ...
> * by 32 bits.
> */
>
> > + if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> > + return -ERANGE;
>
> Note that technically you only need to check period_ns because the core
> already ensures that duty_ns <= period_ns.
>
> > +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> > + struct pwm_device *pwm, enum pwm_polarity
polarity)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + unsigned int channel = pwm->hwpwm;
> > + unsigned long flags;
> > + u32 tcon;
> > +
> > + if (channel > 0)
> > + ++channel;
>
> You have to repeat that in quite a few places, so I wonder if it'd make
> sense to wrap it into a function and add a comment about why the
> increment is necessary.
>
> > +static struct pwm_ops pwm_samsung_ops = {
>
> "static const" please.
>
> > +#ifdef CONFIG_OF
> > +static const struct samsung_pwm_variant s3c24xx_variant = {
> > + .bits = 16,
> > + .div_base = 1,
> > + .has_tint_cstat = false,
> > + .tclk_mask = (1 << 4),
> > +};
> > +
> > +static const struct samsung_pwm_variant s3c64xx_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p64x0_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = 0,
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 5),
> > +};
> > +
> > +static const struct of_device_id samsung_pwm_matches[] = {
> > + { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> > + { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> > + { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> > + { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> > + { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant
> > },
> > + {},
> > +};
> > +#endif
> > +
> > +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> > +{
> > + struct device_node *np = chip->chip.dev->of_node;
> > + const struct of_device_id *match;
> > + struct property *prop;
> > + const __be32 *cur;
> > + u32 val;
> > +
> > + match = of_match_node(samsung_pwm_matches, np);
> > + if (!match)
> > + return -ENODEV;
> > +
> > + memcpy(&chip->variant, match->data, sizeof(chip->variant));
> > +
> > + of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur,
val)
> > {
> > + if (val >= SAMSUNG_PWM_NUM) {
> > + pr_warning("%s: invalid channel index in
samsung,pwm-outputs
> > property\n", +
__func__);
> > + continue;
> > + }
> > + chip->variant.output_mask |= 1 << val;
>
> Could the output_mask be moved to the struct samsung_pwm_chip instead?
> The reason I ask is because it would allow you to make the variant
> constant throughout the driver.
>
> > +static int pwm_samsung_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct samsung_pwm_chip *chip;
> > + struct resource *res;
> > + int ret;
> > +
> > + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> > + if (chip == NULL) {
> > + dev_err(dev, "failed to allocate driver data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->chip.dev = &pdev->dev;
> > + chip->chip.ops = &pwm_samsung_ops;
> > + chip->chip.base = -1;
> > + chip->chip.npwm = SAMSUNG_PWM_NUM;
> > +
> > + if (pdev->dev.of_node) {
>
> Maybe add an IS_ENABLED(CONFIG_OF) check here? That'd allow all OF-
> related code to be thrown away if OF isn't selected.
>
> > + ret = pwm_samsung_parse_dt(chip);
> > + if (ret)
> > + return ret;
> > +
> > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > + chip->chip.of_pwm_n_cells = 3;
> > + } else {
> > + if (!pdev->dev.platform_data) {
> > + dev_err(&pdev->dev, "no platform data
specified\n");
> > + return -EINVAL;
> > + }
> > +
> > + memcpy(&chip->variant, pdev->dev.platform_data,
> > + sizeof(chip-
>variant));
> > + }
>
> Obviously this needs some modification in order for the variant to
> become constant. But I think you can easily do so by making the driver
> match using the platform_driver's id_table field, similar to how the
> matching is done for OF.
>
> > + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> > + if (!chip->base) {
> > + dev_err(&pdev->dev, "failed to request and map
registers\n");
> > + return -ENOMEM;
> > + }
>
> devm_request_and_ioremap() is now deprecated and in the process of being
> removed. You should use devm_ioremap_resource() instead.
>
> > +
> > + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> > + if (IS_ERR(chip->base_clk)) {
> > + dev_err(dev, "failed to get timer base clk\n");
> > + return PTR_ERR(chip->base_clk);
> > + }
> > + clk_prepare_enable(chip->base_clk);
>
> You need to check the return value of clk_prepare_enable(). And if I was
> very pedantic, there should be a blank line before this one.
>
> > + ret = pwmchip_add(&chip->chip);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to register pwm\n");
>
> "failed to register PWM chip" please.
>
> > + goto err_clk_disable;
> > + }
> > +
> > + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> > + clk_get_rate(chip->base_clk),
> > + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> > + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> > +
> > + platform_set_drvdata(pdev, chip);
> > +
> > + return 0;
> > +
> > +err_clk_disable:
> > + clk_disable_unprepare(chip->base_clk);
> > +
> > + return ret;
>
> There's only a single case where this can actually happen, so I don't
> think you need the label here. Just put the clk_disable_unprepare() call
> and the return statement where you jump to the label.
>
> > +#ifdef CONFIG_PM
>
> I think this should really be CONFIG_PM_SLEEP.
>
> > +static struct dev_pm_ops pwm_samsung_pm_ops = {
>
> "static const" please.
>
> Thierry
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 17:59 ` Tomasz Figa
@ 2013-06-18 18:06 ` Kukjin Kim
2013-06-18 18:13 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Kukjin Kim @ 2013-06-18 18:06 UTC (permalink / raw)
To: linux-arm-kernel
On 06/19/13 02:59, Tomasz Figa wrote:
> Hi Thierry,
>
[...]
>>> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
>>> + unsigned int channel, u8 divisor)
>>
>> Nit: please align arguments on subsequent lines with the first argument
>> of the first line. There's many more of these but I haven't mentioned
>> them all explicitly.
>
> Hmm, I'm addressing all your comments that aren't addressed yet in v2 at
> the moment and I'm wondering if this is really the correct way of breaking
> function headers...
>
static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
unsigned int channel, u8 divisor)
I also would preferred to use above style :)
- Kukjin
> According to Documentation/CodingStyle:
>
> /* Quotation starts */
> Statements longer than 80 columns will be broken into sensible chunks,
> unless exceeding 80 columns significantly increases readability and does
> not hide information. Descendants are always substantially shorter than
> the parent and are placed substantially to the right. The same applies to
> function headers with a long argument list. However, never break user-
> visible strings such as printk messages, because that breaks the ability
> to grep for them.
> /* Quotation ends */
>
> Do I understand this incorrectly or does the above fragment state that
> broken lines must be aligned to the right?
>
> Best regards,
> Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 18:06 ` Kukjin Kim
@ 2013-06-18 18:13 ` Tomasz Figa
2013-06-18 21:33 ` Thierry Reding
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 18:13 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 19 of June 2013 03:06:31 Kukjin Kim wrote:
> On 06/19/13 02:59, Tomasz Figa wrote:
> > Hi Thierry,
>
> [...]
>
> >>> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> >>> + unsigned int channel, u8 divisor)
> >>
> >> Nit: please align arguments on subsequent lines with the first
> >> argument
> >> of the first line. There's many more of these but I haven't mentioned
> >> them all explicitly.
> >
> > Hmm, I'm addressing all your comments that aren't addressed yet in v2
> > at the moment and I'm wondering if this is really the correct way of
> > breaking function headers...
>
> static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> unsigned int channel, u8 divisor)
>
>
> I also would preferred to use above style :)
Personally I find it looking better as well, but this is about being
compliant with kernel coding style guidelines (which also says that
indentation should be done using tabs). Please correct my understanding of
the quote below if it is incorrect.
Best regards,
Tomasz
>
> - Kukjin
>
> > According to Documentation/CodingStyle:
> >
> > /* Quotation starts */
> > Statements longer than 80 columns will be broken into sensible chunks,
> > unless exceeding 80 columns significantly increases readability and
> > does not hide information. Descendants are always substantially
> > shorter than the parent and are placed substantially to the right.
> > The same applies to function headers with a long argument list.
> > However, never break user- visible strings such as printk messages,
> > because that breaks the ability to grep for them.
> > /* Quotation ends */
> >
> > Do I understand this incorrectly or does the above fragment state that
> > broken lines must be aligned to the right?
> >
> > Best regards,
> > Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-17 20:29 ` Thierry Reding
2013-06-17 20:50 ` Tomasz Figa
2013-06-18 17:59 ` Tomasz Figa
@ 2013-06-18 19:41 ` Tomasz Figa
2013-06-18 21:40 ` Thierry Reding
2 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 19:41 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > This patch introduces new Samsung PWM driver, which uses Samsung
> > PWM/timer master driver to control shared parts of the hardware.
> >
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
>
> Sorry for jumping in so late, I've been busy with other things lately.
>
> > ---
> >
> > drivers/pwm/Makefile | 1 +
> > drivers/pwm/pwm-samsung.c | 528
> > ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> > insertions(+)
> > create mode 100644 drivers/pwm/pwm-samsung.c
> >
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 229a599..833c3ac 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
> >
> > obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
> > obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung-legacy.o
> >
> > +obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> >
> > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> > obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> > obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> >
> > diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> > new file mode 100644
> > index 0000000..61bed3d
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-samsung.c
> > @@ -0,0 +1,528 @@
> > +/* drivers/pwm/pwm-samsung.c
>
> Nit: this line can be dropped. It serves no purpose.
>
> > + *
> > + * Copyright (c) 2007 Ben Dooks
> > + * Copyright (c) 2008 Simtec Electronics
> > + * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> > + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> > + *
> > + * PWM driver 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 as
> > published by + * the Free Software Foundation; either version 2 of
> > the License. +*/
>
> Nit: the */ should align with the * above.
>
> > +struct samsung_pwm_channel {
> > + unsigned long period_ns;
> > + unsigned long duty_ns;
> > + unsigned long tin_ns;
> > +};
> > +
> > +struct samsung_pwm_chip {
> > + struct pwm_chip chip;
> > + struct samsung_pwm_variant variant;
> > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
>
> The new driver for Renesas did something similar, but I want to
> discourage storing per-channel data within the chip structure.
>
> The PWM framework provides a way to store this information along with
> the PWM device (see pwm_{set,get}_chip_data()).
OK, this looks good, but in my case is not really useful. I need to access
those channel data in my suspend/resume callbacks and obviously I don't
have access to any pwm_device there. Any suggestions?
Best regards,
Tomasz
> > +
> > + void __iomem *base;
> > + struct clk *base_clk;
> > + struct clk *tclk0;
> > + struct clk *tclk1;
> > +};
> > +#define to_samsung_pwm_chip(chip) \
> > + container_of(chip, struct samsung_pwm_chip, chip)
>
> Can you turn this into a static inline function please?
>
> > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > +#endif
>
> Why is this lock global? Shouldn't it more correctly be part of
> samsung_pwm_chip?
>
> > +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > + unsigned int channel, u8 divisor)
>
> Nit: please align arguments on subsequent lines with the first argument
> of the first line. There's many more of these but I haven't mentioned
> them all explicitly.
>
> > +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
>
> Any particular reason for making this inline?
>
> > +static int pwm_samsung_config(struct pwm_chip *chip, struct
> > pwm_device *pwm, + int duty_ns, int period_ns)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + struct samsung_pwm_channel *chan = &our_chip->channels[pwm-
>hwpwm];
> > + unsigned long tin_ns = chan->tin_ns;
> > + unsigned int tcon_chan = pwm->hwpwm;
> > + unsigned long tin_rate;
> > + unsigned long period;
> > + unsigned long flags;
> > + unsigned long tcnt;
>
> Many of these unsigned long variable could be declared on a single line
> to make the function shorter.
>
> > + long tcmp;
> > + u32 tcon;
> > +
> > + /* We currently avoid using 64bit arithmetic by using the
> > + * fact that anything faster than 1Hz is easily representable
> > + * by 32bits. */
>
> Can you turn these into proper block-style comments? Like so:
>
> /*
> * We currently...
> * ...
> * by 32 bits.
> */
>
> > + if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> > + return -ERANGE;
>
> Note that technically you only need to check period_ns because the core
> already ensures that duty_ns <= period_ns.
>
> > +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> > + struct pwm_device *pwm, enum pwm_polarity
polarity)
> > +{
> > + struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > + unsigned int channel = pwm->hwpwm;
> > + unsigned long flags;
> > + u32 tcon;
> > +
> > + if (channel > 0)
> > + ++channel;
>
> You have to repeat that in quite a few places, so I wonder if it'd make
> sense to wrap it into a function and add a comment about why the
> increment is necessary.
>
> > +static struct pwm_ops pwm_samsung_ops = {
>
> "static const" please.
>
> > +#ifdef CONFIG_OF
> > +static const struct samsung_pwm_variant s3c24xx_variant = {
> > + .bits = 16,
> > + .div_base = 1,
> > + .has_tint_cstat = false,
> > + .tclk_mask = (1 << 4),
> > +};
> > +
> > +static const struct samsung_pwm_variant s3c64xx_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5),
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p64x0_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = 0,
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p_variant = {
> > + .bits = 32,
> > + .div_base = 0,
> > + .has_tint_cstat = true,
> > + .tclk_mask = (1 << 5),
> > +};
> > +
> > +static const struct of_device_id samsung_pwm_matches[] = {
> > + { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> > + { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> > + { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> > + { .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> > + { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant
> > },
> > + {},
> > +};
> > +#endif
> > +
> > +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> > +{
> > + struct device_node *np = chip->chip.dev->of_node;
> > + const struct of_device_id *match;
> > + struct property *prop;
> > + const __be32 *cur;
> > + u32 val;
> > +
> > + match = of_match_node(samsung_pwm_matches, np);
> > + if (!match)
> > + return -ENODEV;
> > +
> > + memcpy(&chip->variant, match->data, sizeof(chip->variant));
> > +
> > + of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur,
val)
> > {
> > + if (val >= SAMSUNG_PWM_NUM) {
> > + pr_warning("%s: invalid channel index in
samsung,pwm-outputs
> > property\n", +
__func__);
> > + continue;
> > + }
> > + chip->variant.output_mask |= 1 << val;
>
> Could the output_mask be moved to the struct samsung_pwm_chip instead?
> The reason I ask is because it would allow you to make the variant
> constant throughout the driver.
>
> > +static int pwm_samsung_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct samsung_pwm_chip *chip;
> > + struct resource *res;
> > + int ret;
> > +
> > + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> > + if (chip == NULL) {
> > + dev_err(dev, "failed to allocate driver data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + chip->chip.dev = &pdev->dev;
> > + chip->chip.ops = &pwm_samsung_ops;
> > + chip->chip.base = -1;
> > + chip->chip.npwm = SAMSUNG_PWM_NUM;
> > +
> > + if (pdev->dev.of_node) {
>
> Maybe add an IS_ENABLED(CONFIG_OF) check here? That'd allow all OF-
> related code to be thrown away if OF isn't selected.
>
> > + ret = pwm_samsung_parse_dt(chip);
> > + if (ret)
> > + return ret;
> > +
> > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > + chip->chip.of_pwm_n_cells = 3;
> > + } else {
> > + if (!pdev->dev.platform_data) {
> > + dev_err(&pdev->dev, "no platform data
specified\n");
> > + return -EINVAL;
> > + }
> > +
> > + memcpy(&chip->variant, pdev->dev.platform_data,
> > + sizeof(chip-
>variant));
> > + }
>
> Obviously this needs some modification in order for the variant to
> become constant. But I think you can easily do so by making the driver
> match using the platform_driver's id_table field, similar to how the
> matching is done for OF.
>
> > + chip->base = devm_request_and_ioremap(&pdev->dev, res);
> > + if (!chip->base) {
> > + dev_err(&pdev->dev, "failed to request and map
registers\n");
> > + return -ENOMEM;
> > + }
>
> devm_request_and_ioremap() is now deprecated and in the process of being
> removed. You should use devm_ioremap_resource() instead.
>
> > +
> > + chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> > + if (IS_ERR(chip->base_clk)) {
> > + dev_err(dev, "failed to get timer base clk\n");
> > + return PTR_ERR(chip->base_clk);
> > + }
> > + clk_prepare_enable(chip->base_clk);
>
> You need to check the return value of clk_prepare_enable(). And if I was
> very pedantic, there should be a blank line before this one.
>
> > + ret = pwmchip_add(&chip->chip);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to register pwm\n");
>
> "failed to register PWM chip" please.
>
> > + goto err_clk_disable;
> > + }
> > +
> > + dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> > + clk_get_rate(chip->base_clk),
> > + !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> > + !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> > +
> > + platform_set_drvdata(pdev, chip);
> > +
> > + return 0;
> > +
> > +err_clk_disable:
> > + clk_disable_unprepare(chip->base_clk);
> > +
> > + return ret;
>
> There's only a single case where this can actually happen, so I don't
> think you need the label here. Just put the clk_disable_unprepare() call
> and the return statement where you jump to the label.
>
> > +#ifdef CONFIG_PM
>
> I think this should really be CONFIG_PM_SLEEP.
>
> > +static struct dev_pm_ops pwm_samsung_pm_ops = {
>
> "static const" please.
>
> Thierry
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 18:13 ` Tomasz Figa
@ 2013-06-18 21:33 ` Thierry Reding
2013-06-18 21:35 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Thierry Reding @ 2013-06-18 21:33 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jun 18, 2013 at 08:13:51PM +0200, Tomasz Figa wrote:
> On Wednesday 19 of June 2013 03:06:31 Kukjin Kim wrote:
> > On 06/19/13 02:59, Tomasz Figa wrote:
> > > Hi Thierry,
> >
> > [...]
> >
> > >>> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > >>> + unsigned int channel, u8 divisor)
> > >>
> > >> Nit: please align arguments on subsequent lines with the first
> > >> argument
> > >> of the first line. There's many more of these but I haven't mentioned
> > >> them all explicitly.
> > >
> > > Hmm, I'm addressing all your comments that aren't addressed yet in v2
> > > at the moment and I'm wondering if this is really the correct way of
> > > breaking function headers...
> >
> > static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > unsigned int channel, u8 divisor)
> >
> >
> > I also would preferred to use above style :)
>
> Personally I find it looking better as well, but this is about being
> compliant with kernel coding style guidelines (which also says that
> indentation should be done using tabs). Please correct my understanding of
> the quote below if it is incorrect.
"placed substantially to the right" doesn't imply right-aligned. My
understanding is that it should be indented enough to make it stand
apart. I don't recall ever seeing right-aligned code.
And regarding tabs, you should be indenting using tabs as far as
possible and use spaces for the final alignment, so:
static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
unsigned int channel, u8 divisor)
In case your emailer doesn't highlight it, that's four tabs and four
spaces.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130618/274c58b2/attachment-0001.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 21:33 ` Thierry Reding
@ 2013-06-18 21:35 ` Tomasz Figa
0 siblings, 0 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 21:35 UTC (permalink / raw)
To: linux-arm-kernel
On Tuesday 18 of June 2013 23:33:45 Thierry Reding wrote:
> On Tue, Jun 18, 2013 at 08:13:51PM +0200, Tomasz Figa wrote:
> > On Wednesday 19 of June 2013 03:06:31 Kukjin Kim wrote:
> > > On 06/19/13 02:59, Tomasz Figa wrote:
> > > > Hi Thierry,
> > >
> > > [...]
> > >
> > > >>> +static void pwm_samsung_set_divisor(struct samsung_pwm_chip
> > > >>> *pwm,
> > > >>> + unsigned int channel, u8
divisor)
> > > >>
> > > >> Nit: please align arguments on subsequent lines with the first
> > > >> argument
> > > >> of the first line. There's many more of these but I haven't
> > > >> mentioned
> > > >> them all explicitly.
> > > >
> > > > Hmm, I'm addressing all your comments that aren't addressed yet in
> > > > v2
> > > > at the moment and I'm wondering if this is really the correct way
> > > > of
> > > > breaking function headers...
> > >
> > > static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > >
> > > unsigned int channel, u8 divisor)
> > >
> > > I also would preferred to use above style :)
> >
> > Personally I find it looking better as well, but this is about being
> > compliant with kernel coding style guidelines (which also says that
> > indentation should be done using tabs). Please correct my
> > understanding of the quote below if it is incorrect.
>
> "placed substantially to the right" doesn't imply right-aligned. My
> understanding is that it should be indented enough to make it stand
> apart. I don't recall ever seeing right-aligned code.
>
> And regarding tabs, you should be indenting using tabs as far as
> possible and use spaces for the final alignment, so:
>
> static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> unsigned int channel, u8 divisor)
>
> In case your emailer doesn't highlight it, that's four tabs and four
> spaces.
OK. Thank you for clearing up my misunderstanding.
Btw. I see it as spaces-only in my mail client somehow.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 19:41 ` Tomasz Figa
@ 2013-06-18 21:40 ` Thierry Reding
2013-06-18 21:42 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Thierry Reding @ 2013-06-18 21:40 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jun 18, 2013 at 09:41:09PM +0200, Tomasz Figa wrote:
> On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
[...]
> > > +struct samsung_pwm_channel {
> > > + unsigned long period_ns;
> > > + unsigned long duty_ns;
> > > + unsigned long tin_ns;
> > > +};
> > > +
> > > +struct samsung_pwm_chip {
> > > + struct pwm_chip chip;
> > > + struct samsung_pwm_variant variant;
> > > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
> >
> > The new driver for Renesas did something similar, but I want to
> > discourage storing per-channel data within the chip structure.
> >
> > The PWM framework provides a way to store this information along with
> > the PWM device (see pwm_{set,get}_chip_data()).
>
> OK, this looks good, but in my case is not really useful. I need to access
> those channel data in my suspend/resume callbacks and obviously I don't
> have access to any pwm_device there. Any suggestions?
You do have access to the struct pwm_chip, and that already has an array
of struct pwm_devices, so you could obtain the driver-specific data from
those (see pwm_chip.pwms).
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130618/92a41386/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 21:40 ` Thierry Reding
@ 2013-06-18 21:42 ` Tomasz Figa
2013-06-18 22:20 ` Thierry Reding
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 21:42 UTC (permalink / raw)
To: linux-arm-kernel
On Tuesday 18 of June 2013 23:40:23 Thierry Reding wrote:
> On Tue, Jun 18, 2013 at 09:41:09PM +0200, Tomasz Figa wrote:
> > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> [...]
>
> > > > +struct samsung_pwm_channel {
> > > > + unsigned long period_ns;
> > > > + unsigned long duty_ns;
> > > > + unsigned long tin_ns;
> > > > +};
> > > > +
> > > > +struct samsung_pwm_chip {
> > > > + struct pwm_chip chip;
> > > > + struct samsung_pwm_variant variant;
> > > > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
> > >
> > > The new driver for Renesas did something similar, but I want to
> > > discourage storing per-channel data within the chip structure.
> > >
> > > The PWM framework provides a way to store this information along
> > > with
> > > the PWM device (see pwm_{set,get}_chip_data()).
> >
> > OK, this looks good, but in my case is not really useful. I need to
> > access those channel data in my suspend/resume callbacks and
> > obviously I don't have access to any pwm_device there. Any
> > suggestions?
>
> You do have access to the struct pwm_chip, and that already has an array
> of struct pwm_devices, so you could obtain the driver-specific data
> from those (see pwm_chip.pwms).
Well, if it's legal to access internals of pwm_chip from PWM drivers then
there is no problem. Based on other subsystems, like regulators or clocks
I have concluded that this structure should be dereferenced only inside
PWM core.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-17 20:50 ` Tomasz Figa
@ 2013-06-18 22:17 ` Thierry Reding
2013-06-18 22:45 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Thierry Reding @ 2013-06-18 22:17 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
[...]
> > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > +#endif
> >
> > Why is this lock global? Shouldn't it more correctly be part of
> > samsung_pwm_chip?
>
> There are few registers shared with samsung_pwm_timer clocksource driver
> and so normally the spinlock is exported from it. However on on some
> platforms (namely Exynos >=4x12) kernel can be compiled without that
> driver, so the lock must be defined locally, just to synchronize multiple
> PWM channels, as they share registers as well.
Okay, I think this needs further explanation. The clocksource driver is
used for what exactly? From a quick look it seems to be very much PWM-
specific. According to the device tree binding for the PWM driver, the
timer blocks can also be used as clock sources and clock event timers.
So if I understand correctly you have setups where you use one or more
channels as clock source or clock event timer and one or more channels
as PWM outputs.
In that case it's a very bad idea to use a global lock to synchronize
accesses. You need to do much more than that. To properly split this
across several drivers there needs to be a mechanism to allocate
channels for use either as clock source/event timer or PWM. Otherwise,
how do you know that drivers aren't stepping on each other's toes?
> > > + ret = pwm_samsung_parse_dt(chip);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > + chip->chip.of_pwm_n_cells = 3;
> > > + } else {
> > > + if (!pdev->dev.platform_data) {
> > > + dev_err(&pdev->dev, "no platform data
> specified\n");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > + sizeof(chip-
> >variant));
> > > + }
> >
> > Obviously this needs some modification in order for the variant to
> > become constant. But I think you can easily do so by making the driver
> > match using the platform_driver's id_table field, similar to how the
> > matching is done for OF.
>
> Generally output_mask is board-dependent and is passed inside a variant
> struct using platform_data pointer.
That's okay. But output_mask is the only thing that's board-dependent.
Everything else in the variant is SoC dependent judging by the OF device
table. So really only the output_mask should be part of the platform
data.
> Same platform data is used in samsung_pwm_timer clocksource driver, so I
> just reused it here without adding the need to rename platform device at
> runtime (see arch/arm/plat-samsung/devs.c).
Looking a bit at git log for the clocksource driver, there's this
commit:
a3ce54f clocksource: samsung_pwm_timer: Do not request PWM mem region
That's an ugly workaround for sharing registers between two drivers.
There's a reason why drivers do request_mem_region(), and it is
precisely to prevent them from accessing the same registers. As I
already said above, I think you need to come up with some sort of API to
share resources between the drivers.
There was a similar issue a few months back with the pwm-tiehrpwm and
pwm-tiecap drivers, which use a shared block of registers. Initially
something similar was done as you do here, but eventually we came up
with a much better solution that involved introducing a new driver for
the shared functionality and an exported API.
The situation seems to be somewhat different here since you actually
share the same resources for different functionality instead of sharing
one subset of register across multiple drivers, but I think a similar
solution can be applied here.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130619/a85e8a07/attachment-0001.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 21:42 ` Tomasz Figa
@ 2013-06-18 22:20 ` Thierry Reding
0 siblings, 0 replies; 51+ messages in thread
From: Thierry Reding @ 2013-06-18 22:20 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jun 18, 2013 at 11:42:37PM +0200, Tomasz Figa wrote:
> On Tuesday 18 of June 2013 23:40:23 Thierry Reding wrote:
> > On Tue, Jun 18, 2013 at 09:41:09PM +0200, Tomasz Figa wrote:
> > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > [...]
> >
> > > > > +struct samsung_pwm_channel {
> > > > > + unsigned long period_ns;
> > > > > + unsigned long duty_ns;
> > > > > + unsigned long tin_ns;
> > > > > +};
> > > > > +
> > > > > +struct samsung_pwm_chip {
> > > > > + struct pwm_chip chip;
> > > > > + struct samsung_pwm_variant variant;
> > > > > + struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
> > > >
> > > > The new driver for Renesas did something similar, but I want to
> > > > discourage storing per-channel data within the chip structure.
> > > >
> > > > The PWM framework provides a way to store this information along
> > > > with
> > > > the PWM device (see pwm_{set,get}_chip_data()).
> > >
> > > OK, this looks good, but in my case is not really useful. I need to
> > > access those channel data in my suspend/resume callbacks and
> > > obviously I don't have access to any pwm_device there. Any
> > > suggestions?
> >
> > You do have access to the struct pwm_chip, and that already has an array
> > of struct pwm_devices, so you could obtain the driver-specific data
> > from those (see pwm_chip.pwms).
>
> Well, if it's legal to access internals of pwm_chip from PWM drivers then
> there is no problem. Based on other subsystems, like regulators or clocks
> I have concluded that this structure should be dereferenced only inside
> PWM core.
It's quite alright to do that. As a matter of fact you already do the
same within the .probe() callback to set things up.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130619/a5db36b1/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 22:17 ` Thierry Reding
@ 2013-06-18 22:45 ` Tomasz Figa
2013-06-19 9:43 ` Thierry Reding
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-18 22:45 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> [...]
>
> > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > +#endif
> > >
> > > Why is this lock global? Shouldn't it more correctly be part of
> > > samsung_pwm_chip?
> >
> > There are few registers shared with samsung_pwm_timer clocksource
> > driver and so normally the spinlock is exported from it. However on
> > on some platforms (namely Exynos >=4x12) kernel can be compiled
> > without that driver, so the lock must be defined locally, just to
> > synchronize multiple PWM channels, as they share registers as well.
>
> Okay, I think this needs further explanation. The clocksource driver is
> used for what exactly? From a quick look it seems to be very much PWM-
> specific. According to the device tree binding for the PWM driver, the
> timer blocks can also be used as clock sources and clock event timers.
> So if I understand correctly you have setups where you use one or more
> channels as clock source or clock event timer and one or more channels
> as PWM outputs.
>
> In that case it's a very bad idea to use a global lock to synchronize
> accesses. You need to do much more than that. To properly split this
> across several drivers there needs to be a mechanism to allocate
> channels for use either as clock source/event timer or PWM. Otherwise,
> how do you know that drivers aren't stepping on each other's toes?
>
> > > > + ret = pwm_samsung_parse_dt(chip);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > > + chip->chip.of_pwm_n_cells = 3;
> > > > + } else {
> > > > + if (!pdev->dev.platform_data) {
> > > > + dev_err(&pdev->dev, "no platform data
> >
> > specified\n");
> >
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > > +
sizeof(chip-
> > >
> > >variant));
> > >
> > > > + }
> > >
> > > Obviously this needs some modification in order for the variant to
> > > become constant. But I think you can easily do so by making the
> > > driver
> > > match using the platform_driver's id_table field, similar to how the
> > > matching is done for OF.
> >
> > Generally output_mask is board-dependent and is passed inside a
> > variant
> > struct using platform_data pointer.
>
> That's okay. But output_mask is the only thing that's board-dependent.
> Everything else in the variant is SoC dependent judging by the OF device
> table. So really only the output_mask should be part of the platform
> data.
>
> > Same platform data is used in samsung_pwm_timer clocksource driver, so
> > I just reused it here without adding the need to rename platform
> > device at runtime (see arch/arm/plat-samsung/devs.c).
>
> Looking a bit at git log for the clocksource driver, there's this
> commit:
>
> a3ce54f clocksource: samsung_pwm_timer: Do not request PWM mem
region
>
> That's an ugly workaround for sharing registers between two drivers.
> There's a reason why drivers do request_mem_region(), and it is
> precisely to prevent them from accessing the same registers. As I
> already said above, I think you need to come up with some sort of API to
> share resources between the drivers.
>
> There was a similar issue a few months back with the pwm-tiehrpwm and
> pwm-tiecap drivers, which use a shared block of registers. Initially
> something similar was done as you do here, but eventually we came up
> with a much better solution that involved introducing a new driver for
> the shared functionality and an exported API.
>
> The situation seems to be somewhat different here since you actually
> share the same resources for different functionality instead of sharing
> one subset of register across multiple drivers, but I think a similar
> solution can be applied here.
Well, current design, or rather lack of thereof, has been established
after a significant amount of discussion, mostly with ARM SoC and MFD
maintainers.
It started from a simple reorganization of the clocksource driver to be
multiplatform friendly, without any means of synchronizing both drivers
other than local_irq_save() and _restore() that used to be there
originally, before I started my work on this. This was enough to work
correctly, because both drivers at the same time are used only on
uniprocessor systems.
Here's the thread with patches:
http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/focus=17267
Then I opened a Pandora's Box by asking for opinion in this thread:
http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/focus=16500
After that I started working on a complex framework for sharing this IP
block that would solve all the problems with synchronization, channel
allocation, device tree parsing, variant management, etc.
Here's an initial version, which started as an MFD master driver, which
would let 2 client drivers use the hardware (only the clocksource part was
implemented in that series):
http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/focus=229250
Still, that version didn't receive too good feedback, with comments
pointing me to change the architecture to master-slave, with the
clocksource driver being the master and PWM driver being the slave. And so
v5 was made:
http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
This version was generally accepted, but then we discussed on IRC (mostly
me and Arnd) whether such complex infrastructure is really needed and
concluded that for this platform a simple shared spinlock would be enough,
based on following reasons:
- on all SoCs on which the clocksource driver is going to be used there is
only one instance of the PWM block, with 5 channels
- on all existing boards there are always at least two channels that don't
have outputs
- operations on particular PWM channels must be synchronized anyway,
because there are registers shared by all PWM channels (TCON being most
important where enable, autoreload and invert bits are located for all
channels).
And so we got to current design which is basically a shared spinlock and
per-board output_mask, which specifies which channels have outputs on
particular boards. If you look to the clocksource driver, you can see that
it tries to allocate two output-less channels for timekeeping purposes and
if it fails to do so, it simply panics.
IMHO this solution is fine, because it's simple, has little overhead and
it just works in case of platforms for which it is needed.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-18 22:45 ` Tomasz Figa
@ 2013-06-19 9:43 ` Thierry Reding
2013-06-19 10:23 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Thierry Reding @ 2013-06-19 9:43 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Jun 19, 2013 at 12:45:02AM +0200, Tomasz Figa wrote:
> On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> > On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > [...]
> >
> > > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > > +#endif
> > > >
> > > > Why is this lock global? Shouldn't it more correctly be part of
> > > > samsung_pwm_chip?
> > >
> > > There are few registers shared with samsung_pwm_timer clocksource
> > > driver and so normally the spinlock is exported from it. However on
> > > on some platforms (namely Exynos >=4x12) kernel can be compiled
> > > without that driver, so the lock must be defined locally, just to
> > > synchronize multiple PWM channels, as they share registers as well.
> >
> > Okay, I think this needs further explanation. The clocksource driver is
> > used for what exactly? From a quick look it seems to be very much PWM-
> > specific. According to the device tree binding for the PWM driver, the
> > timer blocks can also be used as clock sources and clock event timers.
> > So if I understand correctly you have setups where you use one or more
> > channels as clock source or clock event timer and one or more channels
> > as PWM outputs.
> >
> > In that case it's a very bad idea to use a global lock to synchronize
> > accesses. You need to do much more than that. To properly split this
> > across several drivers there needs to be a mechanism to allocate
> > channels for use either as clock source/event timer or PWM. Otherwise,
> > how do you know that drivers aren't stepping on each other's toes?
> >
> > > > > + ret = pwm_samsung_parse_dt(chip);
> > > > > + if (ret)
> > > > > + return ret;
> > > > > +
> > > > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > > > + chip->chip.of_pwm_n_cells = 3;
> > > > > + } else {
> > > > > + if (!pdev->dev.platform_data) {
> > > > > + dev_err(&pdev->dev, "no platform data
> > >
> > > specified\n");
> > >
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > > > +
> sizeof(chip-
> > > >
> > > >variant));
> > > >
> > > > > + }
> > > >
> > > > Obviously this needs some modification in order for the variant to
> > > > become constant. But I think you can easily do so by making the
> > > > driver
> > > > match using the platform_driver's id_table field, similar to how the
> > > > matching is done for OF.
> > >
> > > Generally output_mask is board-dependent and is passed inside a
> > > variant
> > > struct using platform_data pointer.
> >
> > That's okay. But output_mask is the only thing that's board-dependent.
> > Everything else in the variant is SoC dependent judging by the OF device
> > table. So really only the output_mask should be part of the platform
> > data.
> >
> > > Same platform data is used in samsung_pwm_timer clocksource driver, so
> > > I just reused it here without adding the need to rename platform
> > > device at runtime (see arch/arm/plat-samsung/devs.c).
> >
> > Looking a bit at git log for the clocksource driver, there's this
> > commit:
> >
> > a3ce54f clocksource: samsung_pwm_timer: Do not request PWM mem
> region
> >
> > That's an ugly workaround for sharing registers between two drivers.
> > There's a reason why drivers do request_mem_region(), and it is
> > precisely to prevent them from accessing the same registers. As I
> > already said above, I think you need to come up with some sort of API to
> > share resources between the drivers.
> >
> > There was a similar issue a few months back with the pwm-tiehrpwm and
> > pwm-tiecap drivers, which use a shared block of registers. Initially
> > something similar was done as you do here, but eventually we came up
> > with a much better solution that involved introducing a new driver for
> > the shared functionality and an exported API.
> >
> > The situation seems to be somewhat different here since you actually
> > share the same resources for different functionality instead of sharing
> > one subset of register across multiple drivers, but I think a similar
> > solution can be applied here.
>
> Well, current design, or rather lack of thereof, has been established
> after a significant amount of discussion, mostly with ARM SoC and MFD
> maintainers.
>
> It started from a simple reorganization of the clocksource driver to be
> multiplatform friendly, without any means of synchronizing both drivers
> other than local_irq_save() and _restore() that used to be there
> originally, before I started my work on this. This was enough to work
> correctly, because both drivers at the same time are used only on
> uniprocessor systems.
>
> Here's the thread with patches:
> http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/focus=17267
>
> Then I opened a Pandora's Box by asking for opinion in this thread:
> http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/focus=16500
>
> After that I started working on a complex framework for sharing this IP
> block that would solve all the problems with synchronization, channel
> allocation, device tree parsing, variant management, etc.
>
> Here's an initial version, which started as an MFD master driver, which
> would let 2 client drivers use the hardware (only the clocksource part was
> implemented in that series):
> http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/focus=229250
>
> Still, that version didn't receive too good feedback, with comments
> pointing me to change the architecture to master-slave, with the
> clocksource driver being the master and PWM driver being the slave. And so
> v5 was made:
> http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
Yeah, this seemed to be going in the right direction.
> This version was generally accepted, but then we discussed on IRC (mostly
> me and Arnd) whether such complex infrastructure is really needed and
> concluded that for this platform a simple shared spinlock would be enough,
> based on following reasons:
> - on all SoCs on which the clocksource driver is going to be used there is
> only one instance of the PWM block, with 5 channels
You say that now. But then at some point somebody decides that it might
be useful to have a second instance.
> - on all existing boards there are always at least two channels that don't
> have outputs
I don't see how that's relevant here.
> - operations on particular PWM channels must be synchronized anyway,
> because there are registers shared by all PWM channels (TCON being most
> important where enable, autoreload and invert bits are located for all
> channels).
And that's precisely why there should be a more explicit way of
synchronizing than just acquiring a lock. Otherwise you have no
possibility whatsoever to detect when a board tries to use both the
clocksource and PWM drivers in incompatible ways. The lock may prevent
concurrent accesses to the shared registers, but that won't help you if
the PWM driver suddenly decides to use an output that was originally
meant to be used as clock source.
> And so we got to current design which is basically a shared spinlock and
> per-board output_mask, which specifies which channels have outputs on
> particular boards. If you look to the clocksource driver, you can see that
> it tries to allocate two output-less channels for timekeeping purposes and
> if it fails to do so, it simply panics.
>
> IMHO this solution is fine, because it's simple, has little overhead and
> it just works in case of platforms for which it is needed.
Okay, I like simple. But I see too much potential for this to break
in the future. There are just too many assumptions for my taste. It
isn't anything that I'm looking forward to have to maintain.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130619/ced4d303/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-19 9:43 ` Thierry Reding
@ 2013-06-19 10:23 ` Tomasz Figa
2013-06-24 17:52 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-19 10:23 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 19 of June 2013 11:43:56 Thierry Reding wrote:
> On Wed, Jun 19, 2013 at 12:45:02AM +0200, Tomasz Figa wrote:
> > On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> > > On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > > [...]
> > >
> > > > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > > > +#endif
> > > > >
> > > > > Why is this lock global? Shouldn't it more correctly be part of
> > > > > samsung_pwm_chip?
> > > >
> > > > There are few registers shared with samsung_pwm_timer clocksource
> > > > driver and so normally the spinlock is exported from it. However on
> > > > on some platforms (namely Exynos >=4x12) kernel can be compiled
> > > > without that driver, so the lock must be defined locally, just to
> > > > synchronize multiple PWM channels, as they share registers as well.
> > >
> > > Okay, I think this needs further explanation. The clocksource driver
> > > is
> > > used for what exactly? From a quick look it seems to be very much
> > > PWM-
> > > specific. According to the device tree binding for the PWM driver,
> > > the
> > > timer blocks can also be used as clock sources and clock event
> > > timers.
> > > So if I understand correctly you have setups where you use one or
> > > more
> > > channels as clock source or clock event timer and one or more
> > > channels
> > > as PWM outputs.
> > >
> > > In that case it's a very bad idea to use a global lock to synchronize
> > > accesses. You need to do much more than that. To properly split this
> > > across several drivers there needs to be a mechanism to allocate
> > > channels for use either as clock source/event timer or PWM.
> > > Otherwise,
> > > how do you know that drivers aren't stepping on each other's toes?
> > >
> > > > > > + ret = pwm_samsung_parse_dt(chip);
> > > > > > + if (ret)
> > > > > > + return ret;
> > > > > > +
> > > > > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > > > > + chip->chip.of_pwm_n_cells = 3;
> > > > > > + } else {
> > > > > > + if (!pdev->dev.platform_data) {
> > > > > > + dev_err(&pdev->dev, "no platform data
> > > >
> > > > specified\n");
> > > >
> > > > > > + return -EINVAL;
> > > > > > + }
> > > > > > +
> > > > > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > > > > +
> >
> > sizeof(chip-
> >
> > > > >variant));
> > > > >
> > > > > > + }
> > > > >
> > > > > Obviously this needs some modification in order for the variant
> > > > > to
> > > > > become constant. But I think you can easily do so by making the
> > > > > driver
> > > > > match using the platform_driver's id_table field, similar to how
> > > > > the
> > > > > matching is done for OF.
> > > >
> > > > Generally output_mask is board-dependent and is passed inside a
> > > > variant
> > > > struct using platform_data pointer.
> > >
> > > That's okay. But output_mask is the only thing that's
> > > board-dependent.
> > > Everything else in the variant is SoC dependent judging by the OF
> > > device
> > > table. So really only the output_mask should be part of the platform
> > > data.
> > >
> > > > Same platform data is used in samsung_pwm_timer clocksource driver,
> > > > so
> > > > I just reused it here without adding the need to rename platform
> > > > device at runtime (see arch/arm/plat-samsung/devs.c).
> > >
> > > Looking a bit at git log for the clocksource driver, there's this
> > >
> > > commit:
> > > a3ce54f clocksource: samsung_pwm_timer: Do not request PWM mem
> >
> > region
> >
> > > That's an ugly workaround for sharing registers between two drivers.
> > > There's a reason why drivers do request_mem_region(), and it is
> > > precisely to prevent them from accessing the same registers. As I
> > > already said above, I think you need to come up with some sort of API
> > > to
> > > share resources between the drivers.
> > >
> > > There was a similar issue a few months back with the pwm-tiehrpwm and
> > > pwm-tiecap drivers, which use a shared block of registers. Initially
> > > something similar was done as you do here, but eventually we came up
> > > with a much better solution that involved introducing a new driver
> > > for
> > > the shared functionality and an exported API.
> > >
> > > The situation seems to be somewhat different here since you actually
> > > share the same resources for different functionality instead of
> > > sharing
> > > one subset of register across multiple drivers, but I think a similar
> > > solution can be applied here.
> >
> > Well, current design, or rather lack of thereof, has been established
> > after a significant amount of discussion, mostly with ARM SoC and MFD
> > maintainers.
> >
> > It started from a simple reorganization of the clocksource driver to be
> > multiplatform friendly, without any means of synchronizing both drivers
> > other than local_irq_save() and _restore() that used to be there
> > originally, before I started my work on this. This was enough to work
> > correctly, because both drivers at the same time are used only on
> > uniprocessor systems.
> >
> > Here's the thread with patches:
> > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/focus=1726
> > 7
> >
> > Then I opened a Pandora's Box by asking for opinion in this thread:
> > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/focus=1650
> > 0
> >
> > After that I started working on a complex framework for sharing this IP
> > block that would solve all the problems with synchronization, channel
> > allocation, device tree parsing, variant management, etc.
> >
> > Here's an initial version, which started as an MFD master driver, which
> > would let 2 client drivers use the hardware (only the clocksource part
> > was implemented in that series):
> > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/focus=2292
> > 50
> >
> > Still, that version didn't receive too good feedback, with comments
> > pointing me to change the architecture to master-slave, with the
> > clocksource driver being the master and PWM driver being the slave. And
> > so v5 was made:
> > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
>
> Yeah, this seemed to be going in the right direction.
>
> > This version was generally accepted, but then we discussed on IRC
> > (mostly me and Arnd) whether such complex infrastructure is really
> > needed and concluded that for this platform a simple shared spinlock
> > would be enough, based on following reasons:
> > - on all SoCs on which the clocksource driver is going to be used there
> > is only one instance of the PWM block, with 5 channels
>
> You say that now. But then at some point somebody decides that it might
> be useful to have a second instance.
No, he won't.
Simply because no new SoC is going to be made which will use the
samsung_pwm_timer driver and all existing ones have only a single instance
of this IP.
> > - on all existing boards there are always at least two channels that
> > don't have outputs
>
> I don't see how that's relevant here.
This is the information passed through output_mask. Clocksource driver can
use _only_ channels without output and PWM driver can use _only_ channels
with output.
Both drivers receive the same output_mask value, either from the same
variant structure or from device tree.
> > - operations on particular PWM channels must be synchronized anyway,
> > because there are registers shared by all PWM channels (TCON being most
> > important where enable, autoreload and invert bits are located for all
> > channels).
>
> And that's precisely why there should be a more explicit way of
> synchronizing than just acquiring a lock. Otherwise you have no
> possibility whatsoever to detect when a board tries to use both the
> clocksource and PWM drivers in incompatible ways. The lock may prevent
> concurrent accesses to the shared registers, but that won't help you if
> the PWM driver suddenly decides to use an output that was originally
> meant to be used as clock source.
See above.
> > And so we got to current design which is basically a shared spinlock
> > and
> > per-board output_mask, which specifies which channels have outputs on
> > particular boards. If you look to the clocksource driver, you can see
> > that it tries to allocate two output-less channels for timekeeping
> > purposes and if it fails to do so, it simply panics.
> >
> > IMHO this solution is fine, because it's simple, has little overhead
> > and
> > it just works in case of platforms for which it is needed.
>
> Okay, I like simple. But I see too much potential for this to break
> in the future. There are just too many assumptions for my taste. It
> isn't anything that I'm looking forward to have to maintain.
Those are completely safe assumptions for existing platforms. Any new
platform with the same PWM IP will use this driver exclusively, without the
clocksource driver and so without the problems you mentioned.
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-19 10:23 ` Tomasz Figa
@ 2013-06-24 17:52 ` Tomasz Figa
2013-06-24 19:50 ` Thierry Reding
0 siblings, 1 reply; 51+ messages in thread
From: Tomasz Figa @ 2013-06-24 17:52 UTC (permalink / raw)
To: linux-arm-kernel
Hi Thierry,
On Wednesday 19 of June 2013 12:23:52 Tomasz Figa wrote:
> On Wednesday 19 of June 2013 11:43:56 Thierry Reding wrote:
> > On Wed, Jun 19, 2013 at 12:45:02AM +0200, Tomasz Figa wrote:
> > > On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> > > > On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > > > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > > > [...]
> > > >
> > > > > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > > > > +#endif
> > > > > >
> > > > > > Why is this lock global? Shouldn't it more correctly be part
> > > > > > of
> > > > > > samsung_pwm_chip?
> > > > >
> > > > > There are few registers shared with samsung_pwm_timer
> > > > > clocksource
> > > > > driver and so normally the spinlock is exported from it. However
> > > > > on
> > > > > on some platforms (namely Exynos >=4x12) kernel can be compiled
> > > > > without that driver, so the lock must be defined locally, just
> > > > > to
> > > > > synchronize multiple PWM channels, as they share registers as
> > > > > well.
> > > >
> > > > Okay, I think this needs further explanation. The clocksource
> > > > driver
> > > > is
> > > > used for what exactly? From a quick look it seems to be very much
> > > > PWM-
> > > > specific. According to the device tree binding for the PWM driver,
> > > > the
> > > > timer blocks can also be used as clock sources and clock event
> > > > timers.
> > > > So if I understand correctly you have setups where you use one or
> > > > more
> > > > channels as clock source or clock event timer and one or more
> > > > channels
> > > > as PWM outputs.
> > > >
> > > > In that case it's a very bad idea to use a global lock to
> > > > synchronize
> > > > accesses. You need to do much more than that. To properly split
> > > > this
> > > > across several drivers there needs to be a mechanism to allocate
> > > > channels for use either as clock source/event timer or PWM.
> > > > Otherwise,
> > > > how do you know that drivers aren't stepping on each other's toes?
> > > >
> > > > > > > + ret = pwm_samsung_parse_dt(chip);
> > > > > > > + if (ret)
> > > > > > > + return ret;
> > > > > > > +
> > > > > > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > > > > > + chip->chip.of_pwm_n_cells = 3;
> > > > > > > + } else {
> > > > > > > + if (!pdev->dev.platform_data) {
> > > > > > > + dev_err(&pdev->dev, "no platform data
> > > > >
> > > > > specified\n");
> > > > >
> > > > > > > + return -EINVAL;
> > > > > > > + }
> > > > > > > +
> > > > > > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > > > > > +
> > >
> > > sizeof(chip-
> > >
> > > > > >variant));
> > > > > >
> > > > > > > + }
> > > > > >
> > > > > > Obviously this needs some modification in order for the
> > > > > > variant
> > > > > > to
> > > > > > become constant. But I think you can easily do so by making
> > > > > > the
> > > > > > driver
> > > > > > match using the platform_driver's id_table field, similar to
> > > > > > how
> > > > > > the
> > > > > > matching is done for OF.
> > > > >
> > > > > Generally output_mask is board-dependent and is passed inside a
> > > > > variant
> > > > > struct using platform_data pointer.
> > > >
> > > > That's okay. But output_mask is the only thing that's
> > > > board-dependent.
> > > > Everything else in the variant is SoC dependent judging by the OF
> > > > device
> > > > table. So really only the output_mask should be part of the
> > > > platform
> > > > data.
> > > >
> > > > > Same platform data is used in samsung_pwm_timer clocksource
> > > > > driver,
> > > > > so
> > > > > I just reused it here without adding the need to rename platform
> > > > > device at runtime (see arch/arm/plat-samsung/devs.c).
> > > >
> > > > Looking a bit at git log for the clocksource driver, there's this
> > > >
> > > > commit:
> > > > a3ce54f clocksource: samsung_pwm_timer: Do not request PWM
mem
> > >
> > > region
> > >
> > > > That's an ugly workaround for sharing registers between two
> > > > drivers.
> > > > There's a reason why drivers do request_mem_region(), and it is
> > > > precisely to prevent them from accessing the same registers. As I
> > > > already said above, I think you need to come up with some sort of
> > > > API
> > > > to
> > > > share resources between the drivers.
> > > >
> > > > There was a similar issue a few months back with the pwm-tiehrpwm
> > > > and
> > > > pwm-tiecap drivers, which use a shared block of registers.
> > > > Initially
> > > > something similar was done as you do here, but eventually we came
> > > > up
> > > > with a much better solution that involved introducing a new driver
> > > > for
> > > > the shared functionality and an exported API.
> > > >
> > > > The situation seems to be somewhat different here since you
> > > > actually
> > > > share the same resources for different functionality instead of
> > > > sharing
> > > > one subset of register across multiple drivers, but I think a
> > > > similar
> > > > solution can be applied here.
> > >
> > > Well, current design, or rather lack of thereof, has been
> > > established
> > > after a significant amount of discussion, mostly with ARM SoC and
> > > MFD
> > > maintainers.
> > >
> > > It started from a simple reorganization of the clocksource driver to
> > > be
> > > multiplatform friendly, without any means of synchronizing both
> > > drivers
> > > other than local_irq_save() and _restore() that used to be there
> > > originally, before I started my work on this. This was enough to
> > > work
> > > correctly, because both drivers at the same time are used only on
> > > uniprocessor systems.
> > >
> > > Here's the thread with patches:
> > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/focus=1
> > > 726
> > > 7
> > >
> > > Then I opened a Pandora's Box by asking for opinion in this thread:
> > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/focus=1
> > > 650
> > > 0
> > >
> > > After that I started working on a complex framework for sharing this
> > > IP
> > > block that would solve all the problems with synchronization,
> > > channel
> > > allocation, device tree parsing, variant management, etc.
> > >
> > > Here's an initial version, which started as an MFD master driver,
> > > which
> > > would let 2 client drivers use the hardware (only the clocksource
> > > part
> > > was implemented in that series):
> > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/focus=2
> > > 292
> > > 50
> > >
> > > Still, that version didn't receive too good feedback, with comments
> > > pointing me to change the architecture to master-slave, with the
> > > clocksource driver being the master and PWM driver being the slave.
> > > And
> > > so v5 was made:
> > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
> >
> > Yeah, this seemed to be going in the right direction.
> >
> > > This version was generally accepted, but then we discussed on IRC
> > > (mostly me and Arnd) whether such complex infrastructure is really
> > > needed and concluded that for this platform a simple shared spinlock
> > > would be enough, based on following reasons:
> > > - on all SoCs on which the clocksource driver is going to be used
> > > there
> > > is only one instance of the PWM block, with 5 channels
> >
> > You say that now. But then at some point somebody decides that it
> > might
> > be useful to have a second instance.
>
> No, he won't.
>
> Simply because no new SoC is going to be made which will use the
> samsung_pwm_timer driver and all existing ones have only a single
> instance of this IP.
>
> > > - on all existing boards there are always at least two channels that
> > > don't have outputs
> >
> > I don't see how that's relevant here.
>
> This is the information passed through output_mask. Clocksource driver
> can use _only_ channels without output and PWM driver can use _only_
> channels with output.
>
> Both drivers receive the same output_mask value, either from the same
> variant structure or from device tree.
>
> > > - operations on particular PWM channels must be synchronized anyway,
> > > because there are registers shared by all PWM channels (TCON being
> > > most
> > > important where enable, autoreload and invert bits are located for
> > > all
> > > channels).
> >
> > And that's precisely why there should be a more explicit way of
> > synchronizing than just acquiring a lock. Otherwise you have no
> > possibility whatsoever to detect when a board tries to use both the
> > clocksource and PWM drivers in incompatible ways. The lock may prevent
> > concurrent accesses to the shared registers, but that won't help you
> > if
> > the PWM driver suddenly decides to use an output that was originally
> > meant to be used as clock source.
>
> See above.
>
> > > And so we got to current design which is basically a shared spinlock
> > > and
> > > per-board output_mask, which specifies which channels have outputs
> > > on
> > > particular boards. If you look to the clocksource driver, you can
> > > see
> > > that it tries to allocate two output-less channels for timekeeping
> > > purposes and if it fails to do so, it simply panics.
> > >
> > > IMHO this solution is fine, because it's simple, has little overhead
> > > and
> > > it just works in case of platforms for which it is needed.
> >
> > Okay, I like simple. But I see too much potential for this to break
> > in the future. There are just too many assumptions for my taste. It
> > isn't anything that I'm looking forward to have to maintain.
>
> Those are completely safe assumptions for existing platforms. Any new
> platform with the same PWM IP will use this driver exclusively, without
> the clocksource driver and so without the problems you mentioned.
Would you mind taking into account things I pointed in reply above?
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-24 17:52 ` Tomasz Figa
@ 2013-06-24 19:50 ` Thierry Reding
2013-06-24 20:03 ` Tomasz Figa
0 siblings, 1 reply; 51+ messages in thread
From: Thierry Reding @ 2013-06-24 19:50 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jun 24, 2013 at 07:52:11PM +0200, Tomasz Figa wrote:
> Hi Thierry,
>
> On Wednesday 19 of June 2013 12:23:52 Tomasz Figa wrote:
> > On Wednesday 19 of June 2013 11:43:56 Thierry Reding wrote:
> > > On Wed, Jun 19, 2013 at 12:45:02AM +0200, Tomasz Figa wrote:
> > > > On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> > > > > On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > > > > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > > > > [...]
> > > > >
> > > > > > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > > > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > > > > > +#endif
> > > > > > >
> > > > > > > Why is this lock global? Shouldn't it more correctly be part
> > > > > > > of
> > > > > > > samsung_pwm_chip?
> > > > > >
> > > > > > There are few registers shared with samsung_pwm_timer
> > > > > > clocksource
> > > > > > driver and so normally the spinlock is exported from it. However
> > > > > > on
> > > > > > on some platforms (namely Exynos >=4x12) kernel can be compiled
> > > > > > without that driver, so the lock must be defined locally, just
> > > > > > to
> > > > > > synchronize multiple PWM channels, as they share registers as
> > > > > > well.
> > > > >
> > > > > Okay, I think this needs further explanation. The clocksource
> > > > > driver
> > > > > is
> > > > > used for what exactly? From a quick look it seems to be very much
> > > > > PWM-
> > > > > specific. According to the device tree binding for the PWM driver,
> > > > > the
> > > > > timer blocks can also be used as clock sources and clock event
> > > > > timers.
> > > > > So if I understand correctly you have setups where you use one or
> > > > > more
> > > > > channels as clock source or clock event timer and one or more
> > > > > channels
> > > > > as PWM outputs.
> > > > >
> > > > > In that case it's a very bad idea to use a global lock to
> > > > > synchronize
> > > > > accesses. You need to do much more than that. To properly split
> > > > > this
> > > > > across several drivers there needs to be a mechanism to allocate
> > > > > channels for use either as clock source/event timer or PWM.
> > > > > Otherwise,
> > > > > how do you know that drivers aren't stepping on each other's toes?
> > > > >
> > > > > > > > + ret = pwm_samsung_parse_dt(chip);
> > > > > > > > + if (ret)
> > > > > > > > + return ret;
> > > > > > > > +
> > > > > > > > + chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > > > > > > > + chip->chip.of_pwm_n_cells = 3;
> > > > > > > > + } else {
> > > > > > > > + if (!pdev->dev.platform_data) {
> > > > > > > > + dev_err(&pdev->dev, "no platform data
> > > > > >
> > > > > > specified\n");
> > > > > >
> > > > > > > > + return -EINVAL;
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + memcpy(&chip->variant, pdev->dev.platform_data,
> > > > > > > > +
> > > >
> > > > sizeof(chip-
> > > >
> > > > > > >variant));
> > > > > > >
> > > > > > > > + }
> > > > > > >
> > > > > > > Obviously this needs some modification in order for the
> > > > > > > variant
> > > > > > > to
> > > > > > > become constant. But I think you can easily do so by making
> > > > > > > the
> > > > > > > driver
> > > > > > > match using the platform_driver's id_table field, similar to
> > > > > > > how
> > > > > > > the
> > > > > > > matching is done for OF.
> > > > > >
> > > > > > Generally output_mask is board-dependent and is passed inside a
> > > > > > variant
> > > > > > struct using platform_data pointer.
> > > > >
> > > > > That's okay. But output_mask is the only thing that's
> > > > > board-dependent.
> > > > > Everything else in the variant is SoC dependent judging by the OF
> > > > > device
> > > > > table. So really only the output_mask should be part of the
> > > > > platform
> > > > > data.
> > > > >
> > > > > > Same platform data is used in samsung_pwm_timer clocksource
> > > > > > driver,
> > > > > > so
> > > > > > I just reused it here without adding the need to rename platform
> > > > > > device at runtime (see arch/arm/plat-samsung/devs.c).
> > > > >
> > > > > Looking a bit at git log for the clocksource driver, there's this
> > > > >
> > > > > commit:
> > > > > a3ce54f clocksource: samsung_pwm_timer: Do not request PWM
> mem
> > > >
> > > > region
> > > >
> > > > > That's an ugly workaround for sharing registers between two
> > > > > drivers.
> > > > > There's a reason why drivers do request_mem_region(), and it is
> > > > > precisely to prevent them from accessing the same registers. As I
> > > > > already said above, I think you need to come up with some sort of
> > > > > API
> > > > > to
> > > > > share resources between the drivers.
> > > > >
> > > > > There was a similar issue a few months back with the pwm-tiehrpwm
> > > > > and
> > > > > pwm-tiecap drivers, which use a shared block of registers.
> > > > > Initially
> > > > > something similar was done as you do here, but eventually we came
> > > > > up
> > > > > with a much better solution that involved introducing a new driver
> > > > > for
> > > > > the shared functionality and an exported API.
> > > > >
> > > > > The situation seems to be somewhat different here since you
> > > > > actually
> > > > > share the same resources for different functionality instead of
> > > > > sharing
> > > > > one subset of register across multiple drivers, but I think a
> > > > > similar
> > > > > solution can be applied here.
> > > >
> > > > Well, current design, or rather lack of thereof, has been
> > > > established
> > > > after a significant amount of discussion, mostly with ARM SoC and
> > > > MFD
> > > > maintainers.
> > > >
> > > > It started from a simple reorganization of the clocksource driver to
> > > > be
> > > > multiplatform friendly, without any means of synchronizing both
> > > > drivers
> > > > other than local_irq_save() and _restore() that used to be there
> > > > originally, before I started my work on this. This was enough to
> > > > work
> > > > correctly, because both drivers at the same time are used only on
> > > > uniprocessor systems.
> > > >
> > > > Here's the thread with patches:
> > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/focus=1
> > > > 726
> > > > 7
> > > >
> > > > Then I opened a Pandora's Box by asking for opinion in this thread:
> > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/focus=1
> > > > 650
> > > > 0
> > > >
> > > > After that I started working on a complex framework for sharing this
> > > > IP
> > > > block that would solve all the problems with synchronization,
> > > > channel
> > > > allocation, device tree parsing, variant management, etc.
> > > >
> > > > Here's an initial version, which started as an MFD master driver,
> > > > which
> > > > would let 2 client drivers use the hardware (only the clocksource
> > > > part
> > > > was implemented in that series):
> > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/focus=2
> > > > 292
> > > > 50
> > > >
> > > > Still, that version didn't receive too good feedback, with comments
> > > > pointing me to change the architecture to master-slave, with the
> > > > clocksource driver being the master and PWM driver being the slave.
> > > > And
> > > > so v5 was made:
> > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
> > >
> > > Yeah, this seemed to be going in the right direction.
> > >
> > > > This version was generally accepted, but then we discussed on IRC
> > > > (mostly me and Arnd) whether such complex infrastructure is really
> > > > needed and concluded that for this platform a simple shared spinlock
> > > > would be enough, based on following reasons:
> > > > - on all SoCs on which the clocksource driver is going to be used
> > > > there
> > > > is only one instance of the PWM block, with 5 channels
> > >
> > > You say that now. But then at some point somebody decides that it
> > > might
> > > be useful to have a second instance.
> >
> > No, he won't.
> >
> > Simply because no new SoC is going to be made which will use the
> > samsung_pwm_timer driver and all existing ones have only a single
> > instance of this IP.
> >
> > > > - on all existing boards there are always at least two channels that
> > > > don't have outputs
> > >
> > > I don't see how that's relevant here.
> >
> > This is the information passed through output_mask. Clocksource driver
> > can use _only_ channels without output and PWM driver can use _only_
> > channels with output.
> >
> > Both drivers receive the same output_mask value, either from the same
> > variant structure or from device tree.
> >
> > > > - operations on particular PWM channels must be synchronized anyway,
> > > > because there are registers shared by all PWM channels (TCON being
> > > > most
> > > > important where enable, autoreload and invert bits are located for
> > > > all
> > > > channels).
> > >
> > > And that's precisely why there should be a more explicit way of
> > > synchronizing than just acquiring a lock. Otherwise you have no
> > > possibility whatsoever to detect when a board tries to use both the
> > > clocksource and PWM drivers in incompatible ways. The lock may prevent
> > > concurrent accesses to the shared registers, but that won't help you
> > > if
> > > the PWM driver suddenly decides to use an output that was originally
> > > meant to be used as clock source.
> >
> > See above.
> >
> > > > And so we got to current design which is basically a shared spinlock
> > > > and
> > > > per-board output_mask, which specifies which channels have outputs
> > > > on
> > > > particular boards. If you look to the clocksource driver, you can
> > > > see
> > > > that it tries to allocate two output-less channels for timekeeping
> > > > purposes and if it fails to do so, it simply panics.
> > > >
> > > > IMHO this solution is fine, because it's simple, has little overhead
> > > > and
> > > > it just works in case of platforms for which it is needed.
> > >
> > > Okay, I like simple. But I see too much potential for this to break
> > > in the future. There are just too many assumptions for my taste. It
> > > isn't anything that I'm looking forward to have to maintain.
> >
> > Those are completely safe assumptions for existing platforms. Any new
> > platform with the same PWM IP will use this driver exclusively, without
> > the clocksource driver and so without the problems you mentioned.
>
> Would you mind taking into account things I pointed in reply above?
I took those into account. But quite frankly they're no excuse for not
having at least a half-decent design. Even if you could guarantee that
the same IP wasn't used in a different combination than you expect,
keeping what you have now sets a very bad example and people will copy
because they don't know better and I'll have to explain this all over
again.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130624/44e97f05/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-24 19:50 ` Thierry Reding
@ 2013-06-24 20:03 ` Tomasz Figa
2013-06-24 20:28 ` Thierry Reding
2013-06-24 20:55 ` Arnd Bergmann
0 siblings, 2 replies; 51+ messages in thread
From: Tomasz Figa @ 2013-06-24 20:03 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 24 of June 2013 21:50:21 Thierry Reding wrote:
> On Mon, Jun 24, 2013 at 07:52:11PM +0200, Tomasz Figa wrote:
> > Hi Thierry,
> >
> > On Wednesday 19 of June 2013 12:23:52 Tomasz Figa wrote:
> > > On Wednesday 19 of June 2013 11:43:56 Thierry Reding wrote:
> > > > On Wed, Jun 19, 2013 at 12:45:02AM +0200, Tomasz Figa wrote:
> > > > > On Wednesday 19 of June 2013 00:17:06 Thierry Reding wrote:
> > > > > > On Mon, Jun 17, 2013 at 10:50:40PM +0200, Tomasz Figa wrote:
> > > > > > > On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> > > > > > > > On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa
wrote:
> > > > > > [...]
> > > > > >
> > > > > > > > > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > > > > > > > > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > > > > > > > > +#endif
> > > > > > > >
> > > > > > > > Why is this lock global? Shouldn't it more correctly be
> > > > > > > > part
> > > > > > > > of
> > > > > > > > samsung_pwm_chip?
> > > > > > >
> > > > > > > There are few registers shared with samsung_pwm_timer
> > > > > > > clocksource
> > > > > > > driver and so normally the spinlock is exported from it.
> > > > > > > However
> > > > > > > on
> > > > > > > on some platforms (namely Exynos >=4x12) kernel can be
> > > > > > > compiled
> > > > > > > without that driver, so the lock must be defined locally,
> > > > > > > just
> > > > > > > to
> > > > > > > synchronize multiple PWM channels, as they share registers
> > > > > > > as
> > > > > > > well.
> > > > > >
> > > > > > Okay, I think this needs further explanation. The clocksource
> > > > > > driver
> > > > > > is
> > > > > > used for what exactly? From a quick look it seems to be very
> > > > > > much
> > > > > > PWM-
> > > > > > specific. According to the device tree binding for the PWM
> > > > > > driver,
> > > > > > the
> > > > > > timer blocks can also be used as clock sources and clock event
> > > > > > timers.
> > > > > > So if I understand correctly you have setups where you use one
> > > > > > or
> > > > > > more
> > > > > > channels as clock source or clock event timer and one or more
> > > > > > channels
> > > > > > as PWM outputs.
> > > > > >
> > > > > > In that case it's a very bad idea to use a global lock to
> > > > > > synchronize
> > > > > > accesses. You need to do much more than that. To properly
> > > > > > split
> > > > > > this
> > > > > > across several drivers there needs to be a mechanism to
> > > > > > allocate
> > > > > > channels for use either as clock source/event timer or PWM.
> > > > > > Otherwise,
> > > > > > how do you know that drivers aren't stepping on each other's
> > > > > > toes?
> > > > > >
> > > > > > > > > + ret = pwm_samsung_parse_dt(chip);
> > > > > > > > > + if (ret)
> > > > > > > > > + return ret;
> > > > > > > > > +
> > > > > > > > > + chip->chip.of_xlate =
of_pwm_xlate_with_flags;
> > > > > > > > > + chip->chip.of_pwm_n_cells = 3;
> > > > > > > > > + } else {
> > > > > > > > > + if (!pdev->dev.platform_data) {
> > > > > > > > > + dev_err(&pdev->dev, "no platform
data
> > > > > > >
> > > > > > > specified\n");
> > > > > > >
> > > > > > > > > + return -EINVAL;
> > > > > > > > > + }
> > > > > > > > > +
> > > > > > > > > + memcpy(&chip->variant, pdev-
>dev.platform_data,
> > > > > > > > > +
> > > > >
> > > > > sizeof(chip-
> > > > >
> > > > > > > >variant));
> > > > > > > >
> > > > > > > > > + }
> > > > > > > >
> > > > > > > > Obviously this needs some modification in order for the
> > > > > > > > variant
> > > > > > > > to
> > > > > > > > become constant. But I think you can easily do so by
> > > > > > > > making
> > > > > > > > the
> > > > > > > > driver
> > > > > > > > match using the platform_driver's id_table field, similar
> > > > > > > > to
> > > > > > > > how
> > > > > > > > the
> > > > > > > > matching is done for OF.
> > > > > > >
> > > > > > > Generally output_mask is board-dependent and is passed
> > > > > > > inside a
> > > > > > > variant
> > > > > > > struct using platform_data pointer.
> > > > > >
> > > > > > That's okay. But output_mask is the only thing that's
> > > > > > board-dependent.
> > > > > > Everything else in the variant is SoC dependent judging by the
> > > > > > OF
> > > > > > device
> > > > > > table. So really only the output_mask should be part of the
> > > > > > platform
> > > > > > data.
> > > > > >
> > > > > > > Same platform data is used in samsung_pwm_timer clocksource
> > > > > > > driver,
> > > > > > > so
> > > > > > > I just reused it here without adding the need to rename
> > > > > > > platform
> > > > > > > device at runtime (see arch/arm/plat-samsung/devs.c).
> > > > > >
> > > > > > Looking a bit at git log for the clocksource driver, there's
> > > > > > this
> > > > > >
> > > > > > commit:
> > > > > > a3ce54f clocksource: samsung_pwm_timer: Do not request PWM
> >
> > mem
> >
> > > > > region
> > > > >
> > > > > > That's an ugly workaround for sharing registers between two
> > > > > > drivers.
> > > > > > There's a reason why drivers do request_mem_region(), and it
> > > > > > is
> > > > > > precisely to prevent them from accessing the same registers.
> > > > > > As I
> > > > > > already said above, I think you need to come up with some sort
> > > > > > of
> > > > > > API
> > > > > > to
> > > > > > share resources between the drivers.
> > > > > >
> > > > > > There was a similar issue a few months back with the
> > > > > > pwm-tiehrpwm
> > > > > > and
> > > > > > pwm-tiecap drivers, which use a shared block of registers.
> > > > > > Initially
> > > > > > something similar was done as you do here, but eventually we
> > > > > > came
> > > > > > up
> > > > > > with a much better solution that involved introducing a new
> > > > > > driver
> > > > > > for
> > > > > > the shared functionality and an exported API.
> > > > > >
> > > > > > The situation seems to be somewhat different here since you
> > > > > > actually
> > > > > > share the same resources for different functionality instead
> > > > > > of
> > > > > > sharing
> > > > > > one subset of register across multiple drivers, but I think a
> > > > > > similar
> > > > > > solution can be applied here.
> > > > >
> > > > > Well, current design, or rather lack of thereof, has been
> > > > > established
> > > > > after a significant amount of discussion, mostly with ARM SoC
> > > > > and
> > > > > MFD
> > > > > maintainers.
> > > > >
> > > > > It started from a simple reorganization of the clocksource
> > > > > driver to
> > > > > be
> > > > > multiplatform friendly, without any means of synchronizing both
> > > > > drivers
> > > > > other than local_irq_save() and _restore() that used to be there
> > > > > originally, before I started my work on this. This was enough to
> > > > > work
> > > > > correctly, because both drivers at the same time are used only
> > > > > on
> > > > > uniprocessor systems.
> > > > >
> > > > > Here's the thread with patches:
> > > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16664/foc
> > > > > us=1
> > > > > 726
> > > > > 7
> > > > >
> > > > > Then I opened a Pandora's Box by asking for opinion in this
> > > > > thread:
> > > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/16480/foc
> > > > > us=1
> > > > > 650
> > > > > 0
> > > > >
> > > > > After that I started working on a complex framework for sharing
> > > > > this
> > > > > IP
> > > > > block that would solve all the problems with synchronization,
> > > > > channel
> > > > > allocation, device tree parsing, variant management, etc.
> > > > >
> > > > > Here's an initial version, which started as an MFD master
> > > > > driver,
> > > > > which
> > > > > would let 2 client drivers use the hardware (only the
> > > > > clocksource
> > > > > part
> > > > > was implemented in that series):
> > > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17464/foc
> > > > > us=2
> > > > > 292
> > > > > 50
> > > > >
> > > > > Still, that version didn't receive too good feedback, with
> > > > > comments
> > > > > pointing me to change the architecture to master-slave, with the
> > > > > clocksource driver being the master and PWM driver being the
> > > > > slave.
> > > > > And
> > > > > so v5 was made:
> > > > > http://thread.gmane.org/gmane.linux.kernel.samsung-soc/17864
> > > >
> > > > Yeah, this seemed to be going in the right direction.
> > > >
> > > > > This version was generally accepted, but then we discussed on
> > > > > IRC
> > > > > (mostly me and Arnd) whether such complex infrastructure is
> > > > > really
> > > > > needed and concluded that for this platform a simple shared
> > > > > spinlock
> > > > > would be enough, based on following reasons:
> > > > > - on all SoCs on which the clocksource driver is going to be
> > > > > used
> > > > > there
> > > > > is only one instance of the PWM block, with 5 channels
> > > >
> > > > You say that now. But then at some point somebody decides that it
> > > > might
> > > > be useful to have a second instance.
> > >
> > > No, he won't.
> > >
> > > Simply because no new SoC is going to be made which will use the
> > > samsung_pwm_timer driver and all existing ones have only a single
> > > instance of this IP.
> > >
> > > > > - on all existing boards there are always at least two channels
> > > > > that
> > > > > don't have outputs
> > > >
> > > > I don't see how that's relevant here.
> > >
> > > This is the information passed through output_mask. Clocksource
> > > driver
> > > can use _only_ channels without output and PWM driver can use _only_
> > > channels with output.
> > >
> > > Both drivers receive the same output_mask value, either from the
> > > same
> > > variant structure or from device tree.
> > >
> > > > > - operations on particular PWM channels must be synchronized
> > > > > anyway,
> > > > > because there are registers shared by all PWM channels (TCON
> > > > > being
> > > > > most
> > > > > important where enable, autoreload and invert bits are located
> > > > > for
> > > > > all
> > > > > channels).
> > > >
> > > > And that's precisely why there should be a more explicit way of
> > > > synchronizing than just acquiring a lock. Otherwise you have no
> > > > possibility whatsoever to detect when a board tries to use both
> > > > the
> > > > clocksource and PWM drivers in incompatible ways. The lock may
> > > > prevent
> > > > concurrent accesses to the shared registers, but that won't help
> > > > you
> > > > if
> > > > the PWM driver suddenly decides to use an output that was
> > > > originally
> > > > meant to be used as clock source.
> > >
> > > See above.
> > >
> > > > > And so we got to current design which is basically a shared
> > > > > spinlock
> > > > > and
> > > > > per-board output_mask, which specifies which channels have
> > > > > outputs
> > > > > on
> > > > > particular boards. If you look to the clocksource driver, you
> > > > > can
> > > > > see
> > > > > that it tries to allocate two output-less channels for
> > > > > timekeeping
> > > > > purposes and if it fails to do so, it simply panics.
> > > > >
> > > > > IMHO this solution is fine, because it's simple, has little
> > > > > overhead
> > > > > and
> > > > > it just works in case of platforms for which it is needed.
> > > >
> > > > Okay, I like simple. But I see too much potential for this to
> > > > break
> > > > in the future. There are just too many assumptions for my taste.
> > > > It
> > > > isn't anything that I'm looking forward to have to maintain.
> > >
> > > Those are completely safe assumptions for existing platforms. Any
> > > new
> > > platform with the same PWM IP will use this driver exclusively,
> > > without
> > > the clocksource driver and so without the problems you mentioned.
> >
> > Would you mind taking into account things I pointed in reply above?
>
> I took those into account. But quite frankly they're no excuse for not
> having at least a half-decent design. Even if you could guarantee that
> the same IP wasn't used in a different combination than you expect,
> keeping what you have now sets a very bad example and people will copy
> because they don't know better and I'll have to explain this all over
> again.
OK. So we just need to prevent people from blindly copying this.
Wouldn't adding a big comment about why this is enough for this platform
and why anything more sophisticated would be just overengineering in this
case be enough?
As you could see in several versions of the series I linked in my previous
replies, anything that looked decently simply added a lot of glue code and
cross module dependencies without serving any useful purpose, other than
just looking good.
This driver is already a lot better than previous one, because as opposed
to the old one, it gives synchronization that is technically correct. Not
even saying about a lot of other things fixed, like multiplatform-
awareness, OF support, coding style, proper handling of dividers, etc.,
etc. It would be really bad if all this was put to waste...
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-24 20:03 ` Tomasz Figa
@ 2013-06-24 20:28 ` Thierry Reding
2013-06-24 20:55 ` Arnd Bergmann
1 sibling, 0 replies; 51+ messages in thread
From: Thierry Reding @ 2013-06-24 20:28 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jun 24, 2013 at 10:03:12PM +0200, Tomasz Figa wrote:
[...]
> OK. So we just need to prevent people from blindly copying this.
>
> Wouldn't adding a big comment about why this is enough for this platform
> and why anything more sophisticated would be just overengineering in this
> case be enough?
That'd be sugarcoating. I don't think this is a good idea at all and
using a properly encapsulated driver with proper shared API to access
shared registers wouldn't be overengineering in my opinion. It would
in fact be good engineering.
> This driver is already a lot better than previous one, because as opposed
> to the old one, it gives synchronization that is technically correct. Not
> even saying about a lot of other things fixed, like multiplatform-
> awareness, OF support, coding style, proper handling of dividers, etc.,
> etc. It would be really bad if all this was put to waste...
I certainly wouldn't want any of this going to waste, and quite frankly
letting you get away with just the comment is already more compromise
than I really like.
The TI drivers used to have a similar problem and I required them to
come up with a good solution. It'd be fair to require the same of you.
But maybe I'm getting soft.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130624/452894d3/attachment.sig>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 08/15] pwm: Add new pwm-samsung driver
2013-06-24 20:03 ` Tomasz Figa
2013-06-24 20:28 ` Thierry Reding
@ 2013-06-24 20:55 ` Arnd Bergmann
1 sibling, 0 replies; 51+ messages in thread
From: Arnd Bergmann @ 2013-06-24 20:55 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 24 June 2013, Tomasz Figa wrote:
> Wouldn't adding a big comment about why this is enough for this platform
> and why anything more sophisticated would be just overengineering in this
> case be enough?
>
> As you could see in several versions of the series I linked in my previous
> replies, anything that looked decently simply added a lot of glue code and
> cross module dependencies without serving any useful purpose, other than
> just looking good.
>
> This driver is already a lot better than previous one, because as opposed
> to the old one, it gives synchronization that is technically correct. Not
> even saying about a lot of other things fixed, like multiplatform-
> awareness, OF support, coding style, proper handling of dividers, etc.,
> etc. It would be really bad if all this was put to waste...
I agree. The shared spinlock as the interface between the two drivers
is clearly a hack, but I think it is an appropriate hack in this special
case and that's why I suggested using that over the more complex solutions
that Tomasz suggested.
The important part is that the DT binding reasonable and could support
more complex scenarios even though they are highly unlikely.
We can always change the kernel code to something else if we need to,
but I could not come up with good *and* simple design. The most obvious
solution would be to make the clocksource driver the master that exports
an interface to the pwm driver, but that just adds complexity for the
common case that just uses the pwm driver but not the clocksource driver.
The attempt to create a separate MFD glue driver that abstracts the
interface in the way that pwm-tiecap does also was a failure here, because
one of the two consumers has to run very early, before we have access to
most of the device infrastructure the kernel provides.
Arnd
^ permalink raw reply [flat|nested] 51+ messages in thread
end of thread, other threads:[~2013-06-24 20:55 UTC | newest]
Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-05 21:18 ` [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
2013-06-05 21:18 ` [PATCH 02/15] ARM: SAMSUNG: Add new PWM platform device Tomasz Figa
2013-06-05 21:18 ` [PATCH 03/15] ARM: SAMSUNG: Set PWM platform data Tomasz Figa
2013-06-05 21:18 ` [PATCH 04/15] ARM: SAMSUNG: Move all platforms to new clocksource driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 05/15] ARM: SAMSUNG: Remove old samsung-time driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 06/15] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code Tomasz Figa
2013-06-05 21:18 ` [PATCH 07/15] pwm: samsung: Rename to pwm-samsung-legacy Tomasz Figa
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
2013-06-13 20:14 ` Heiko Stübner
2013-06-13 20:18 ` Tomasz Figa
2013-06-16 17:19 ` Tomasz Figa
2013-06-16 20:45 ` Kukjin Kim
2013-06-17 20:29 ` Thierry Reding
2013-06-17 20:50 ` Tomasz Figa
2013-06-18 22:17 ` Thierry Reding
2013-06-18 22:45 ` Tomasz Figa
2013-06-19 9:43 ` Thierry Reding
2013-06-19 10:23 ` Tomasz Figa
2013-06-24 17:52 ` Tomasz Figa
2013-06-24 19:50 ` Thierry Reding
2013-06-24 20:03 ` Tomasz Figa
2013-06-24 20:28 ` Thierry Reding
2013-06-24 20:55 ` Arnd Bergmann
2013-06-18 17:59 ` Tomasz Figa
2013-06-18 18:06 ` Kukjin Kim
2013-06-18 18:13 ` Tomasz Figa
2013-06-18 21:33 ` Thierry Reding
2013-06-18 21:35 ` Tomasz Figa
2013-06-18 19:41 ` Tomasz Figa
2013-06-18 21:40 ` Thierry Reding
2013-06-18 21:42 ` Tomasz Figa
2013-06-18 22:20 ` Thierry Reding
2013-06-05 21:18 ` [PATCH 09/15] ARM: SAMSUNG: Rework private data handling in dev-backlight Tomasz Figa
2013-06-05 21:18 ` [PATCH 10/15] ARM: SAMSUNG: Modify board files to use new PWM platform device Tomasz Figa
2013-06-05 21:18 ` [PATCH 11/15] pwm: Remove superseded pwm-samsung-legacy driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 12/15] ARM: SAMSUNG: Remove old PWM timer platform devices Tomasz Figa
2013-06-05 21:18 ` [PATCH 13/15] ARM: SAMSUNG: Remove pwm-clock infrastructure Tomasz Figa
2013-06-05 21:18 ` [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header Tomasz Figa
2013-06-13 20:24 ` Heiko Stübner
2013-06-13 20:38 ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 15/15] ARM: SAMSUNG: Remove " Tomasz Figa
2013-06-12 21:48 ` [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-12 23:00 ` Olof Johansson
2013-06-12 23:13 ` Tomasz Figa
2013-06-12 23:38 ` Heiko Stübner
2013-06-12 23:52 ` Sylwester Nawrocki
2013-06-13 9:07 ` Tomasz Figa
2013-06-13 20:17 ` Heiko Stübner
2013-06-13 22:27 ` Heiko Stübner
2013-06-13 0:25 ` Kukjin Kim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).