This patch introduces new Samsung PWM driver, which is completely
rewritten to be multiplatform- and DeviceTree-aware.
In addition, remaining problems of old driver are fixed, such as:
- proper handling of hardware variants,
- synchronization on SMP systems,
- handling of boundary parameter values,
- hardware sharing with PWM clocksource driver,
- undefined state of PWM output after stopping PWM channel.
Signed-off-by: Tomasz Figa tomasz.f...@gmail.com
Reviewed-by: Sylwester Nawrocki s.nawro...@samsung.com
Acked-by: Thierry Reding thierry.red...@gmail.com
---
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-samsung.c | 618 ++
2 files changed, 619 insertions(+)
create mode 100644 drivers/pwm/pwm-samsung.c
Changes since v5:
- No functional changes, just following cosmetic improvements.
- Used BIT() macro to define bits instead of shifting 1s directly.
- Added comment about bit layout in TCON register.
- Made macros used to define bits have more meaningful parameter names.
- Updated commit message.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index aa94807..86a5771 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_PWM_PUV3)+= pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.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 000..fcc8b9a
--- /dev/null
+++ b/drivers/pwm/pwm-samsung.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2007 Ben Dooks
+ * Copyright (c) 2008 Simtec Electronics
+ * Ben Dooks b...@simtec.co.uk, ben-li...@fluff.org
+ * Copyright (c) 2013 Tomasz Figa tomasz.f...@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/bitops.h
+#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
+
+/* For struct samsung_timer_variant and samsung_pwm_lock. */
+#include clocksource/samsung_pwm.h
+
+#define REG_TCFG0 0x00
+#define REG_TCFG1 0x04
+#define REG_TCON 0x08
+
+#define REG_TCNTB(chan)(0x0c + ((chan) * 0xc))
+#define REG_TCMPB(chan)(0x10 + ((chan) * 0xc))
+
+#define TCFG0_PRESCALER_MASK 0xff
+#define TCFG0_PRESCALER1_SHIFT 8
+
+#define TCFG1_MUX_MASK 0xf
+#define TCFG1_SHIFT(chan) (4 * (chan))
+
+/*
+ * Each channel occupies 4 bits in TCON register, but there is a gap of 4
+ * bits (one channel) after channel 0, so channels have different numbering
+ * when accessing TCON register. See to_tcon_channel() function.
+ *
+ * In addition, the location of autoreload bit for channel 4 (TCON channel 5)
+ * in its set of bits is 2 as opposed to 3 for other channels.
+ */
+#define TCON_START(chan) BIT(4 * (chan) + 0)
+#define TCON_MANUALUPDATE(chan)BIT(4 * (chan) + 1)
+#define TCON_INVERT(chan) BIT(4 * (chan) + 2)
+#define _TCON_AUTORELOAD(chan) BIT(4 * (chan) + 3)
+#define _TCON_AUTORELOAD4(chan)BIT(4 * (chan) + 2)
+#define TCON_AUTORELOAD(chan) \
+ ((chan 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan))
+
+/**
+ * struct samsung_pwm_channel - private data of PWM channel
+ * @period_ns: current period in nanoseconds programmed to the hardware
+ * @duty_ns: current duty time in nanoseconds programmed to the hardware
+ * @tin_ns:time of one timer tick in nanoseconds with current timer rate
+ */
+struct samsung_pwm_channel {
+ u32 period_ns;
+ u32 duty_ns;
+ u32 tin_ns;
+};
+
+/**
+ * struct samsung_pwm_chip - private data of PWM chip
+ * @chip: generic PWM chip
+ * @variant: local copy of hardware variant data
+ * @inverter_mask: inverter status for all channels - one bit per channel
+ * @base: base address of mapped PWM registers
+ * @base_clk: base clock used to drive the timers
+ * @tclk0: external clock 0 (can be ERR_PTR if not present)
+ * @tclk1: external clock 1 (can be ERR_PTR if not present)
+ */
+struct samsung_pwm_chip {
+ struct pwm_chip chip;
+ struct samsung_pwm_variant variant;
+ u8 inverter_mask;
+
+ void