linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/4] PWM: add and enable CSR SiRFSoC PWM driver
@ 2014-07-16  1:55 Huayi Li
  2014-07-16  1:55 ` [PATCH v5 1/4] pwm: add CSR SiRFSoc " Huayi Li
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Huayi Li @ 2014-07-16  1:55 UTC (permalink / raw)
  To: linux-arm-kernel

Changes in v5:
 - select the best source clock which can be divided to a more
   accurate PWM clock
 - only enable PWM clock and its source clock when needed 


Changes in v3:
 - v4: fix many issues from Thierry's feedbacks

Changes in v3:
 - add "depends on" COMPILE_TEST according to Arnd's feedback;
 - move the pwm clock source to dts according to Arnd's feedback;
 - add lost dt-binding document

Changes in v2:
 - clean the source clock of PWM wave, use OSC(26MHz)

Huayi Li (4):
  pwm: add CSR SiRFSoc PWM driver
  pwm: sirf: add dt-binding document
  ARM: dts: sirf: fix the pwm-cells and clocks
  ARM: prima2_defconfig: enable PWM and sirf PWM driver

 Documentation/devicetree/bindings/pwm/pwm-sirf.txt |  29 ++
 arch/arm/boot/dts/atlas6.dtsi                      |   8 +-
 arch/arm/boot/dts/prima2.dtsi                      |   8 +-
 arch/arm/configs/prima2_defconfig                  |   2 +
 drivers/pwm/Kconfig                                |  10 +
 drivers/pwm/Makefile                               |   1 +
 drivers/pwm/pwm-sirf.c                             | 450 +++++++++++++++++++++
 7 files changed, 504 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sirf.txt
 create mode 100644 drivers/pwm/pwm-sirf.c

-- 
1.9.3



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/4] pwm: add CSR SiRFSoc PWM driver
  2014-07-16  1:55 [PATCH v5 0/4] PWM: add and enable CSR SiRFSoC PWM driver Huayi Li
@ 2014-07-16  1:55 ` Huayi Li
  2014-07-24  9:48   ` Barry Song
  2014-07-16  1:55 ` [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks Huayi Li
  2014-07-16  1:55 ` [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver Huayi Li
  2 siblings, 1 reply; 7+ messages in thread
From: Huayi Li @ 2014-07-16  1:55 UTC (permalink / raw)
  To: linux-arm-kernel

PWM controller of CSR SiRFSoC can generate 7 independent outputs. Each output
duty cycle can be adjusted by setting the corresponding wait & hold registers.
There are 6 external channels (0 to 5) and 1 internal channel (6).
Supports a wide frequency range: the source clock divider can be from 2
up to 65536*2.

Signed-off-by: Huayi Li <huayi.li@csr.com>
---
 drivers/pwm/Kconfig    |  10 ++
 drivers/pwm/Makefile   |   1 +
 drivers/pwm/pwm-sirf.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 461 insertions(+)
 create mode 100644 drivers/pwm/pwm-sirf.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 4ad7b89..77d65a6 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -215,6 +215,16 @@ config PWM_SAMSUNG
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-samsung.
 
+config PWM_SIRF
+	tristate "SiRF PWM support"
+	depends on ARCH_SIRF
+	help
+	  Generic PWM framework driver for the PWM controller on SiRF
+	  SoCs.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-sirf.
+
 config PWM_SPEAR
 	tristate "STMicroelectronics SPEAr PWM support"
 	depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 5c86a19..7fa4f14 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -19,6 +19,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.o
+obj-$(CONFIG_PWM_SIRF)		+= pwm-sirf.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-sirf.c b/drivers/pwm/pwm-sirf.c
new file mode 100644
index 0000000..a5a9e2f
--- /dev/null
+++ b/drivers/pwm/pwm-sirf.c
@@ -0,0 +1,450 @@
+/*
+ * SIRF serial SoC PWM device core driver
+ *
+ * Copyright (c) 2014 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define SIRF_PWM_SELECT_PRECLK			0x0
+#define SIRF_PWM_OE				0x4
+#define SIRF_PWM_ENABLE_PRECLOCK		0x8
+#define SIRF_PWM_ENABLE_POSTCLOCK		0xC
+#define SIRF_PWM_GET_WAIT_OFFSET(n)		(0x10 + 0x8*n)
+#define SIRF_PWM_GET_HOLD_OFFSET(n)		(0x14 + 0x8*n)
+
+#define SIRF_PWM_TR_STEP(n)			(0x48 + 0x8*n)
+#define SIRF_PWM_STEP_HOLD(n)			(0x4c + 0x8*n)
+
+#define SRC_FIELD_SIZE				3
+#define BYPASS_MODE_BIT				21
+#define TRANS_MODE_SELECT_BIT			7
+
+#define SIRF_MAX_SRC_CLK			5
+
+struct sirf_pwm_chip {
+	struct pwm_chip	chip;
+	struct mutex mutex;
+	void __iomem *base;
+	struct clk *pwmc_clk;
+};
+
+struct sirf_pwm {
+	u32 sigsrc_clk_idx;
+	struct clk *sigsrc_clk;
+	u32 bypass_mode;
+	u32 duty_ns;
+};
+
+static inline struct sirf_pwm_chip *to_sirf_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct sirf_pwm_chip, chip);
+}
+
+static int sirf_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct sirf_pwm *spwm;
+
+	spwm = devm_kzalloc(chip->dev, sizeof(*spwm), GFP_KERNEL);
+	if (!spwm)
+		return -ENOMEM;
+
+	pwm_set_chip_data(pwm, spwm);
+
+	return 0;
+}
+
+static void sirf_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+
+	if (!spwm)
+		devm_kfree(chip->dev, spwm);
+}
+
+static u32 sirf_pwm_ns_to_cycles(struct pwm_device *pwm, u32 time_ns)
+{
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+	u32 src_clk_rate = clk_get_rate(spwm->sigsrc_clk);
+	u64 cycle;
+
+	cycle = div_u64((u64)src_clk_rate * time_ns, NSEC_PER_SEC);
+
+	return (u32)(cycle > 1 ? cycle : 1);
+}
+
+static void _sirf_pwm_hwconfig(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 period_cycles, high_cycles, low_cycles;
+	struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+
+	period_cycles = sirf_pwm_ns_to_cycles(pwm, pwm_get_period(pwm));
+
+	/*
+	 * enter bypass mode, high_cycles and low_cycle
+	 * do not need to config if period_cycles == 1
+	 */
+	if (period_cycles == 1) {
+		spwm->bypass_mode = 1;
+	} else {
+		spwm->bypass_mode = 0;
+
+		high_cycles = sirf_pwm_ns_to_cycles(pwm, spwm->duty_ns);
+		low_cycles = period_cycles - high_cycles;
+
+		/*
+		 * high_cycles will equal to period_cycles when duty_ns
+		 * is big enough, so low_cycles will be 0,
+		 * a wrong value will be written to register after
+		 * low_cycles minus 1 later.
+		 */
+		if (high_cycles == period_cycles) {
+			high_cycles--;
+			low_cycles = 1;
+		}
+
+		mutex_lock(&spwmc->mutex);
+
+		writel(high_cycles - 1,
+			spwmc->base + SIRF_PWM_GET_WAIT_OFFSET(pwm->hwpwm));
+		writel(low_cycles - 1,
+			spwmc->base + SIRF_PWM_GET_HOLD_OFFSET(pwm->hwpwm));
+
+		mutex_unlock(&spwmc->mutex);
+	}
+}
+
+static int sirf_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			int duty_ns, int period_ns)
+{
+	struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+
+	if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+		u32 src_clk_rate, src_clk_rate_min = ~0;
+		u32 i;
+		u64 cycle;
+		u32 cycle_diff;
+		u32 ns_diff, ns_diff_min = ~0;
+		int ret;
+		char src_clk_name[10];
+		struct clk *sigsrc_clk;
+
+		/*
+		 * select a best source clock for the specific PWM clock
+		 * 1. select the clock with minimal error
+		 * 2. select the slower clock if some of them have
+		 *    the same error
+		 */
+		for (i = 0; i < SIRF_MAX_SRC_CLK; i++) {
+			sprintf(src_clk_name, "sigsrc%d", i);
+			sigsrc_clk = devm_clk_get(chip->dev, src_clk_name);
+			if (IS_ERR(sigsrc_clk))
+				continue;
+
+			src_clk_rate = clk_get_rate(sigsrc_clk);
+
+			cycle = (u64)src_clk_rate * period_ns;
+			div_u64_rem(cycle, NSEC_PER_SEC, &cycle_diff);
+
+			ns_diff = (u32)cycle_diff / src_clk_rate;
+
+			if (ns_diff <= ns_diff_min &&
+					src_clk_rate < src_clk_rate_min) {
+				ns_diff_min = ns_diff;
+				src_clk_rate_min = src_clk_rate;
+				spwm->sigsrc_clk_idx = i;
+				spwm->sigsrc_clk = sigsrc_clk;
+			} else {
+				devm_clk_put(chip->dev, sigsrc_clk);
+			}
+		}
+
+		/*
+		 * enable PWM before writing the register
+		 */
+		ret = clk_prepare_enable(spwmc->pwmc_clk);
+		if (ret)
+			return ret;
+	}
+
+	spwm->duty_ns = duty_ns;
+
+	_sirf_pwm_hwconfig(chip, pwm);
+
+	/*
+	 * if the PWM is not enabled, turn off the clock again
+	 */
+	if (!test_bit(PWMF_ENABLED, &pwm->flags))
+		clk_disable_unprepare(spwmc->pwmc_clk);
+
+	return 0;
+}
+
+static void _sirf_pwm_hwenable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+	u32 val;
+
+	mutex_lock(&spwmc->mutex);
+
+	/* disable preclock */
+	val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+	val &= ~(1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+
+	/* select preclock source must after disable preclk */
+	val = readl(spwmc->base + SIRF_PWM_SELECT_PRECLK);
+	val &= ~(0x7 << (SRC_FIELD_SIZE * pwm->hwpwm));
+	val |= (spwm->sigsrc_clk_idx << (SRC_FIELD_SIZE * pwm->hwpwm));
+
+	if (spwm->bypass_mode == 1)
+		val |= (0x1 << (BYPASS_MODE_BIT + pwm->hwpwm));
+	else
+		val &= ~(0x1 << (BYPASS_MODE_BIT + pwm->hwpwm));
+
+	writel(val, spwmc->base + SIRF_PWM_SELECT_PRECLK);
+
+	/* wait for some time */
+	usleep_range(100, 200);
+
+	/* enable preclock */
+	val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+	val |= (1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+
+	/* enable post clock*/
+	val = readl(spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
+	val |= (1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
+
+	/* enable output */
+	val = readl(spwmc->base + SIRF_PWM_OE);
+	val |= 1 << pwm->hwpwm;
+	val |= 1 << (pwm->hwpwm + TRANS_MODE_SELECT_BIT);
+
+	writel(val, spwmc->base + SIRF_PWM_OE);
+
+	mutex_unlock(&spwmc->mutex);
+}
+
+static int sirf_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+	u32 ret;
+
+	ret = clk_prepare_enable(spwm->sigsrc_clk);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(spwmc->pwmc_clk);
+	if (ret)
+		return ret;
+
+	_sirf_pwm_hwenable(chip, pwm);
+
+	return 0;
+}
+
+static void sirf_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 val;
+	struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
+	struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
+
+	mutex_lock(&spwmc->mutex);
+
+	/* disable output */
+	val = readl(spwmc->base + SIRF_PWM_OE);
+	val &= ~(1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_OE);
+
+	/* disable postclock */
+	val = readl(spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
+	val &= ~(1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
+
+	/* disable preclock */
+	val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+	val &= ~(1 << pwm->hwpwm);
+	writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
+
+	mutex_unlock(&spwmc->mutex);
+
+	clk_disable_unprepare(spwm->sigsrc_clk);
+
+	clk_disable_unprepare(spwmc->pwmc_clk);
+}
+
+static const struct pwm_ops sirf_pwm_ops = {
+	.request = sirf_pwm_request,
+	.free = sirf_pwm_free,
+	.enable = sirf_pwm_enable,
+	.disable = sirf_pwm_disable,
+	.config = sirf_pwm_config,
+	.owner = THIS_MODULE,
+};
+
+static int sirf_pwm_probe(struct platform_device *pdev)
+{
+	struct sirf_pwm_chip *spwmc;
+	struct resource *mem_res;
+	int ret;
+
+	spwmc = devm_kzalloc(&pdev->dev, sizeof(*spwmc),
+			GFP_KERNEL);
+	if (!spwmc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, spwmc);
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	spwmc->base = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (IS_ERR(spwmc->base))
+		return PTR_ERR(spwmc->base);
+
+	/*
+	 * get clock for PWM controller
+	 */
+	spwmc->pwmc_clk = devm_clk_get(&pdev->dev, "pwmc");
+	if (IS_ERR(spwmc->pwmc_clk)) {
+		dev_err(&pdev->dev, "failed to get PWM controller clock\n");
+		return PTR_ERR(spwmc->pwmc_clk);
+	}
+
+	spwmc->chip.dev = &pdev->dev;
+	spwmc->chip.ops = &sirf_pwm_ops;
+	spwmc->chip.base = -1;
+	spwmc->chip.npwm = 7;
+
+	mutex_init(&spwmc->mutex);
+
+	ret = pwmchip_add(&spwmc->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register PWM chip\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int sirf_pwm_remove(struct platform_device *pdev)
+{
+	struct sirf_pwm_chip *spwmc = platform_get_drvdata(pdev);
+
+	return pwmchip_remove(&spwmc->chip);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_pwm_suspend(struct device *dev)
+{
+	struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
+	struct pwm_device *pwm;
+	int i;
+
+	for (i = 0; i < spwmc->chip.npwm; i++) {
+		pwm = &spwmc->chip.pwms[i];
+		/*
+		 * disable PWM which is not disabled when user suspend
+		 */
+		if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
+				test_bit(PWMF_ENABLED, &pwm->flags))
+			sirf_pwm_disable(pwm->chip, pwm);
+	}
+
+	return 0;
+}
+
+static int sirf_pwm_resume(struct device *dev)
+{
+	struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
+	struct pwm_device *pwm;
+	struct sirf_pwm *spwm;
+	int i;
+
+	for (i = 0; i < spwmc->chip.npwm; i++) {
+		pwm = &spwmc->chip.pwms[i];
+		spwm = pwm_get_chip_data(pwm);
+
+		if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
+				test_bit(PWMF_ENABLED, &pwm->flags)) {
+			sirf_pwm_config(&spwmc->chip, pwm, spwm->duty_ns,
+					pwm_get_period(pwm));
+			sirf_pwm_enable(&spwmc->chip, pwm);
+		}
+	}
+
+	return 0;
+}
+
+static int sirf_pwm_restore(struct device *dev)
+{
+	struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
+	struct pwm_device *pwm;
+	struct sirf_pwm *spwm;
+	int i;
+
+	for (i = 0; i < spwmc->chip.npwm; i++) {
+		pwm = &spwmc->chip.pwms[i];
+		spwm = pwm_get_chip_data(pwm);
+		/*
+		 * while restoring from hibernation, state of PWM is enabled,
+		 * but PWM hardware is not re-enabled, register about config
+		 * and enable should be restored here
+		 */
+		if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
+				test_bit(PWMF_ENABLED, &pwm->flags)) {
+			_sirf_pwm_hwconfig(&spwmc->chip, pwm);
+			_sirf_pwm_hwenable(&spwmc->chip, pwm);
+		}
+	}
+
+	return 0;
+}
+#else
+#define sirf_pwm_resume NULL
+#define sirf_pwm_suspend NULL
+#define sirf_pwm_restore NULL
+#endif
+
+static const struct dev_pm_ops sirf_pwm_pm_ops = {
+	.suspend = sirf_pwm_suspend,
+	.resume = sirf_pwm_resume,
+	.restore = sirf_pwm_restore,
+};
+
+static const struct of_device_id sirf_pwm_of_match[] = {
+	{ .compatible = "sirf,prima2-pwm", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_pwm_of_match);
+
+static struct platform_driver sirf_pwm_driver = {
+	.driver = {
+		.name = "sirf-pwm",
+		.pm = &sirf_pwm_pm_ops,
+		.of_match_table = sirf_pwm_of_match,
+	},
+	.probe = sirf_pwm_probe,
+	.remove = sirf_pwm_remove,
+};
+module_platform_driver(sirf_pwm_driver);
+
+MODULE_DESCRIPTION("SIRF serial SoC PWM device core driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_AUTHOR("Huayi Li <huayi.li@csr.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.9.3



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks
  2014-07-16  1:55 [PATCH v5 0/4] PWM: add and enable CSR SiRFSoC PWM driver Huayi Li
  2014-07-16  1:55 ` [PATCH v5 1/4] pwm: add CSR SiRFSoc " Huayi Li
@ 2014-07-16  1:55 ` Huayi Li
  2014-07-24  9:53   ` Barry Song
  2014-07-16  1:55 ` [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver Huayi Li
  2 siblings, 1 reply; 7+ messages in thread
From: Huayi Li @ 2014-07-16  1:55 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds missed pwm-cells, clock-names and signal source
clock for PWM module.

Signed-off-by: Huayi Li <huayi.li@csr.com>
---
 arch/arm/boot/dts/atlas6.dtsi | 8 ++++++--
 arch/arm/boot/dts/prima2.dtsi | 8 ++++++--
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index bb22842..d424a69 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -638,10 +638,14 @@
                                 };
 			};
 
-			pwm at b0130000 {
+			pwm: pwm at b0130000 {
 				compatible = "sirf,prima2-pwm";
+				#pwm-cells = <2>;
 				reg = <0xb0130000 0x10000>;
-				clocks = <&clks 21>;
+				clocks = <&clks 21>, <&clks 1>, <&clks 2>,
+					<&clks 3>, <&clks 0>, <&clks 4>;
+				clock-names = "pwmc", "sigsrc0", "sigsrc1",
+					"sigsrc2", "sigsrc3", "sigsrc4";
 			};
 
 			efusesys at b0140000 {
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 963b7e5..68bb0c4 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -646,10 +646,14 @@
                                 };
 			};
 
-			pwm at b0130000 {
+			pwm: pwm at b0130000 {
 				compatible = "sirf,prima2-pwm";
+				#pwm-cells = <2>;
 				reg = <0xb0130000 0x10000>;
-				clocks = <&clks 21>;
+				clocks = <&clks 21>, <&clks 1>, <&clks 2>,
+					<&clks 3>, <&clks 0>, <&clks 4>;
+				clock-names = "pwmc", "sigsrc0", "sigsrc1",
+					"sigsrc2", "sigsrc3", "sigsrc4";
 			};
 
 			efusesys at b0140000 {
-- 
1.9.3



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver
  2014-07-16  1:55 [PATCH v5 0/4] PWM: add and enable CSR SiRFSoC PWM driver Huayi Li
  2014-07-16  1:55 ` [PATCH v5 1/4] pwm: add CSR SiRFSoc " Huayi Li
  2014-07-16  1:55 ` [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks Huayi Li
@ 2014-07-16  1:55 ` Huayi Li
  2014-07-24  9:31   ` Barry Song
  2 siblings, 1 reply; 7+ messages in thread
From: Huayi Li @ 2014-07-16  1:55 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Huayi Li <huayi.li@csr.com>
---
 arch/arm/configs/prima2_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig
index 23591db..303204a 100644
--- a/arch/arm/configs/prima2_defconfig
+++ b/arch/arm/configs/prima2_defconfig
@@ -50,6 +50,8 @@ CONFIG_DMADEVICES_DEBUG=y
 CONFIG_DMADEVICES_VDEBUG=y
 CONFIG_SIRF_DMA=y
 # CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PWM=y
+CONFIG_PWM_SIRF=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
-- 
1.9.3



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver
  2014-07-16  1:55 ` [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver Huayi Li
@ 2014-07-24  9:31   ` Barry Song
  0 siblings, 0 replies; 7+ messages in thread
From: Barry Song @ 2014-07-24  9:31 UTC (permalink / raw)
  To: linux-arm-kernel

2014-07-16 9:55 GMT+08:00 Huayi Li <huayi.li@csr.com>:
> Signed-off-by: Huayi Li <huayi.li@csr.com>

Acked-by: Barry Song <Baohua.Song@csr.com>

> ---
>  arch/arm/configs/prima2_defconfig | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig
> index 23591db..303204a 100644
> --- a/arch/arm/configs/prima2_defconfig
> +++ b/arch/arm/configs/prima2_defconfig
> @@ -50,6 +50,8 @@ CONFIG_DMADEVICES_DEBUG=y
>  CONFIG_DMADEVICES_VDEBUG=y
>  CONFIG_SIRF_DMA=y
>  # CONFIG_IOMMU_SUPPORT is not set
> +CONFIG_PWM=y
> +CONFIG_PWM_SIRF=y
>  CONFIG_EXT2_FS=y
>  CONFIG_MSDOS_FS=y
>  CONFIG_VFAT_FS=y
> --
> 1.9.3
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/4] pwm: add CSR SiRFSoc PWM driver
  2014-07-16  1:55 ` [PATCH v5 1/4] pwm: add CSR SiRFSoc " Huayi Li
@ 2014-07-24  9:48   ` Barry Song
  0 siblings, 0 replies; 7+ messages in thread
From: Barry Song @ 2014-07-24  9:48 UTC (permalink / raw)
  To: linux-arm-kernel

2014-07-16 9:55 GMT+08:00 Huayi Li <huayi.li@csr.com>:
> PWM controller of CSR SiRFSoC can generate 7 independent outputs. Each output
> duty cycle can be adjusted by setting the corresponding wait & hold registers.
> There are 6 external channels (0 to 5) and 1 internal channel (6).
> Supports a wide frequency range: the source clock divider can be from 2
> up to 65536*2.
>
> Signed-off-by: Huayi Li <huayi.li@csr.com>
> ---
>  drivers/pwm/Kconfig    |  10 ++
>  drivers/pwm/Makefile   |   1 +
>  drivers/pwm/pwm-sirf.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 461 insertions(+)
>  create mode 100644 drivers/pwm/pwm-sirf.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 4ad7b89..77d65a6 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -215,6 +215,16 @@ config PWM_SAMSUNG
>           To compile this driver as a module, choose M here: the module
>           will be called pwm-samsung.
>
> +config PWM_SIRF
> +       tristate "SiRF PWM support"
> +       depends on ARCH_SIRF
> +       help
> +         Generic PWM framework driver for the PWM controller on SiRF
> +         SoCs.
> +
> +         To compile this driver as a module, choose M here: the module
> +         will be called pwm-sirf.
> +
>  config PWM_SPEAR
>         tristate "STMicroelectronics SPEAr PWM support"
>         depends on PLAT_SPEAR
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 5c86a19..7fa4f14 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -19,6 +19,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.o
> +obj-$(CONFIG_PWM_SIRF)         += pwm-sirf.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-sirf.c b/drivers/pwm/pwm-sirf.c
> new file mode 100644
> index 0000000..a5a9e2f
> --- /dev/null
> +++ b/drivers/pwm/pwm-sirf.c
> @@ -0,0 +1,450 @@
> +/*
> + * SIRF serial SoC PWM device core driver
> + *
> + * Copyright (c) 2014 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +
> +#define SIRF_PWM_SELECT_PRECLK                 0x0
> +#define SIRF_PWM_OE                            0x4
> +#define SIRF_PWM_ENABLE_PRECLOCK               0x8
> +#define SIRF_PWM_ENABLE_POSTCLOCK              0xC
> +#define SIRF_PWM_GET_WAIT_OFFSET(n)            (0x10 + 0x8*n)
> +#define SIRF_PWM_GET_HOLD_OFFSET(n)            (0x14 + 0x8*n)
> +
> +#define SIRF_PWM_TR_STEP(n)                    (0x48 + 0x8*n)
> +#define SIRF_PWM_STEP_HOLD(n)                  (0x4c + 0x8*n)
> +
> +#define SRC_FIELD_SIZE                         3
> +#define BYPASS_MODE_BIT                                21
> +#define TRANS_MODE_SELECT_BIT                  7
> +
> +#define SIRF_MAX_SRC_CLK                       5
> +
> +struct sirf_pwm_chip {
> +       struct pwm_chip chip;
> +       struct mutex mutex;
> +       void __iomem *base;
> +       struct clk *pwmc_clk;
> +};
> +
> +struct sirf_pwm {
> +       u32 sigsrc_clk_idx;
> +       struct clk *sigsrc_clk;
> +       u32 bypass_mode;
> +       u32 duty_ns;
> +};
> +
> +static inline struct sirf_pwm_chip *to_sirf_pwm_chip(struct pwm_chip *chip)
> +{
> +       return container_of(chip, struct sirf_pwm_chip, chip);
> +}
> +
> +static int sirf_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       struct sirf_pwm *spwm;
> +
> +       spwm = devm_kzalloc(chip->dev, sizeof(*spwm), GFP_KERNEL);
> +       if (!spwm)
> +               return -ENOMEM;
> +
> +       pwm_set_chip_data(pwm, spwm);
> +
> +       return 0;
> +}
> +
> +static void sirf_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +
> +       if (!spwm)
> +               devm_kfree(chip->dev, spwm);
> +}
> +
> +static u32 sirf_pwm_ns_to_cycles(struct pwm_device *pwm, u32 time_ns)
> +{
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +       u32 src_clk_rate = clk_get_rate(spwm->sigsrc_clk);
> +       u64 cycle;
> +
> +       cycle = div_u64((u64)src_clk_rate * time_ns, NSEC_PER_SEC);
> +
> +       return (u32)(cycle > 1 ? cycle : 1);
> +}
> +
> +static void _sirf_pwm_hwconfig(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       u32 period_cycles, high_cycles, low_cycles;
> +       struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +
> +       period_cycles = sirf_pwm_ns_to_cycles(pwm, pwm_get_period(pwm));
> +
> +       /*
> +        * enter bypass mode, high_cycles and low_cycle
> +        * do not need to config if period_cycles == 1
> +        */
> +       if (period_cycles == 1) {
> +               spwm->bypass_mode = 1;

the bypass mode need some comments here.  or we need to add a "TODO:
move to clk subsystem" here, it is actually not PWM, but a clock
output now.


> +       } else {
> +               spwm->bypass_mode = 0;
> +
> +               high_cycles = sirf_pwm_ns_to_cycles(pwm, spwm->duty_ns);
> +               low_cycles = period_cycles - high_cycles;
> +
> +               /*
> +                * high_cycles will equal to period_cycles when duty_ns
> +                * is big enough, so low_cycles will be 0,
> +                * a wrong value will be written to register after
> +                * low_cycles minus 1 later.
> +                */
> +               if (high_cycles == period_cycles) {
> +                       high_cycles--;
> +                       low_cycles = 1;
> +               }
> +
> +               mutex_lock(&spwmc->mutex);
> +
> +               writel(high_cycles - 1,
> +                       spwmc->base + SIRF_PWM_GET_WAIT_OFFSET(pwm->hwpwm));
> +               writel(low_cycles - 1,
> +                       spwmc->base + SIRF_PWM_GET_HOLD_OFFSET(pwm->hwpwm));
> +
> +               mutex_unlock(&spwmc->mutex);
> +       }
> +}
> +
> +static int sirf_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> +                       int duty_ns, int period_ns)
> +{
> +       struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +
> +       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
> +               u32 src_clk_rate, src_clk_rate_min = ~0;
> +               u32 i;
> +               u64 cycle;
> +               u32 cycle_diff;
> +               u32 ns_diff, ns_diff_min = ~0;
> +               int ret;
> +               char src_clk_name[10];
> +               struct clk *sigsrc_clk;
> +
> +               /*
> +                * select a best source clock for the specific PWM clock
> +                * 1. select the clock with minimal error
> +                * 2. select the slower clock if some of them have
> +                *    the same error
> +                */
> +               for (i = 0; i < SIRF_MAX_SRC_CLK; i++) {
> +                       sprintf(src_clk_name, "sigsrc%d", i);
> +                       sigsrc_clk = devm_clk_get(chip->dev, src_clk_name);
> +                       if (IS_ERR(sigsrc_clk))
> +                               continue;
> +
> +                       src_clk_rate = clk_get_rate(sigsrc_clk);
> +
> +                       cycle = (u64)src_clk_rate * period_ns;
> +                       div_u64_rem(cycle, NSEC_PER_SEC, &cycle_diff);
> +
> +                       ns_diff = (u32)cycle_diff / src_clk_rate;
> +
> +                       if (ns_diff <= ns_diff_min &&
> +                                       src_clk_rate < src_clk_rate_min) {
> +                               ns_diff_min = ns_diff;
> +                               src_clk_rate_min = src_clk_rate;
> +                               spwm->sigsrc_clk_idx = i;
> +                               spwm->sigsrc_clk = sigsrc_clk;
> +                       } else {
> +                               devm_clk_put(chip->dev, sigsrc_clk);
> +                       }
> +               }
> +
> +               /*
> +                * enable PWM before writing the register
> +                */
> +               ret = clk_prepare_enable(spwmc->pwmc_clk);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       spwm->duty_ns = duty_ns;
> +
> +       _sirf_pwm_hwconfig(chip, pwm);

it looks weird if we config pwm if it has been enabled. the whole
produre to select suitable clock source is not executed?
and only duty_ns can be configed?

> +
> +       /*
> +        * if the PWM is not enabled, turn off the clock again
> +        */
> +       if (!test_bit(PWMF_ENABLED, &pwm->flags))
> +               clk_disable_unprepare(spwmc->pwmc_clk);
> +
> +       return 0;
> +}
> +
> +static void _sirf_pwm_hwenable(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +       u32 val;
> +
> +       mutex_lock(&spwmc->mutex);
> +
> +       /* disable preclock */
> +       val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +       val &= ~(1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +
> +       /* select preclock source must after disable preclk */
> +       val = readl(spwmc->base + SIRF_PWM_SELECT_PRECLK);
> +       val &= ~(0x7 << (SRC_FIELD_SIZE * pwm->hwpwm));
> +       val |= (spwm->sigsrc_clk_idx << (SRC_FIELD_SIZE * pwm->hwpwm));
> +
> +       if (spwm->bypass_mode == 1)
> +               val |= (0x1 << (BYPASS_MODE_BIT + pwm->hwpwm));
> +       else
> +               val &= ~(0x1 << (BYPASS_MODE_BIT + pwm->hwpwm));
> +
> +       writel(val, spwmc->base + SIRF_PWM_SELECT_PRECLK);
> +
> +       /* wait for some time */
> +       usleep_range(100, 200);
> +
> +       /* enable preclock */
> +       val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +       val |= (1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +
> +       /* enable post clock*/
> +       val = readl(spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
> +       val |= (1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
> +
> +       /* enable output */
> +       val = readl(spwmc->base + SIRF_PWM_OE);
> +       val |= 1 << pwm->hwpwm;
> +       val |= 1 << (pwm->hwpwm + TRANS_MODE_SELECT_BIT);
> +
> +       writel(val, spwmc->base + SIRF_PWM_OE);
> +
> +       mutex_unlock(&spwmc->mutex);
> +}
> +
> +static int sirf_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +       u32 ret;
> +
> +       ret = clk_prepare_enable(spwm->sigsrc_clk);
> +       if (ret)
> +               return ret;
> +
> +       ret = clk_prepare_enable(spwmc->pwmc_clk);
> +       if (ret)
> +               return ret;
> +
> +       _sirf_pwm_hwenable(chip, pwm);
> +
> +       return 0;
> +}
> +
> +static void sirf_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +       u32 val;
> +       struct sirf_pwm_chip *spwmc = to_sirf_pwm_chip(chip);
> +       struct sirf_pwm *spwm = pwm_get_chip_data(pwm);
> +
> +       mutex_lock(&spwmc->mutex);
> +
> +       /* disable output */
> +       val = readl(spwmc->base + SIRF_PWM_OE);
> +       val &= ~(1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_OE);
> +
> +       /* disable postclock */
> +       val = readl(spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
> +       val &= ~(1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_ENABLE_POSTCLOCK);
> +
> +       /* disable preclock */
> +       val = readl(spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +       val &= ~(1 << pwm->hwpwm);
> +       writel(val, spwmc->base + SIRF_PWM_ENABLE_PRECLOCK);
> +
> +       mutex_unlock(&spwmc->mutex);
> +
> +       clk_disable_unprepare(spwm->sigsrc_clk);
> +
> +       clk_disable_unprepare(spwmc->pwmc_clk);
> +}
> +
> +static const struct pwm_ops sirf_pwm_ops = {
> +       .request = sirf_pwm_request,
> +       .free = sirf_pwm_free,
> +       .enable = sirf_pwm_enable,
> +       .disable = sirf_pwm_disable,
> +       .config = sirf_pwm_config,
> +       .owner = THIS_MODULE,
> +};
> +
> +static int sirf_pwm_probe(struct platform_device *pdev)
> +{
> +       struct sirf_pwm_chip *spwmc;
> +       struct resource *mem_res;
> +       int ret;
> +
> +       spwmc = devm_kzalloc(&pdev->dev, sizeof(*spwmc),
> +                       GFP_KERNEL);
> +       if (!spwmc)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, spwmc);
> +
> +       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       spwmc->base = devm_ioremap_resource(&pdev->dev, mem_res);
> +       if (IS_ERR(spwmc->base))
> +               return PTR_ERR(spwmc->base);
> +
> +       /*
> +        * get clock for PWM controller
> +        */
> +       spwmc->pwmc_clk = devm_clk_get(&pdev->dev, "pwmc");
> +       if (IS_ERR(spwmc->pwmc_clk)) {
> +               dev_err(&pdev->dev, "failed to get PWM controller clock\n");
> +               return PTR_ERR(spwmc->pwmc_clk);
> +       }
> +
> +       spwmc->chip.dev = &pdev->dev;
> +       spwmc->chip.ops = &sirf_pwm_ops;
> +       spwmc->chip.base = -1;
> +       spwmc->chip.npwm = 7;
> +
> +       mutex_init(&spwmc->mutex);
> +
> +       ret = pwmchip_add(&spwmc->chip);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "failed to register PWM chip\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int sirf_pwm_remove(struct platform_device *pdev)
> +{
> +       struct sirf_pwm_chip *spwmc = platform_get_drvdata(pdev);
> +
> +       return pwmchip_remove(&spwmc->chip);
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int sirf_pwm_suspend(struct device *dev)
> +{
> +       struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
> +       struct pwm_device *pwm;
> +       int i;
> +
> +       for (i = 0; i < spwmc->chip.npwm; i++) {
> +               pwm = &spwmc->chip.pwms[i];
> +               /*
> +                * disable PWM which is not disabled when user suspend
> +                */
> +               if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
> +                               test_bit(PWMF_ENABLED, &pwm->flags))
> +                       sirf_pwm_disable(pwm->chip, pwm);
> +       }
> +
> +       return 0;
> +}
> +
> +static int sirf_pwm_resume(struct device *dev)
> +{
> +       struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
> +       struct pwm_device *pwm;
> +       struct sirf_pwm *spwm;
> +       int i;
> +
> +       for (i = 0; i < spwmc->chip.npwm; i++) {
> +               pwm = &spwmc->chip.pwms[i];
> +               spwm = pwm_get_chip_data(pwm);
> +
> +               if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
> +                               test_bit(PWMF_ENABLED, &pwm->flags)) {
> +                       sirf_pwm_config(&spwmc->chip, pwm, spwm->duty_ns,
> +                                       pwm_get_period(pwm));
> +                       sirf_pwm_enable(&spwmc->chip, pwm);
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int sirf_pwm_restore(struct device *dev)
> +{
> +       struct sirf_pwm_chip *spwmc = dev_get_drvdata(dev);
> +       struct pwm_device *pwm;
> +       struct sirf_pwm *spwm;
> +       int i;
> +
> +       for (i = 0; i < spwmc->chip.npwm; i++) {
> +               pwm = &spwmc->chip.pwms[i];
> +               spwm = pwm_get_chip_data(pwm);
> +               /*
> +                * while restoring from hibernation, state of PWM is enabled,
> +                * but PWM hardware is not re-enabled, register about config
> +                * and enable should be restored here
> +                */
> +               if (test_bit(PWMF_REQUESTED, &pwm->flags) &&
> +                               test_bit(PWMF_ENABLED, &pwm->flags)) {
> +                       _sirf_pwm_hwconfig(&spwmc->chip, pwm);
> +                       _sirf_pwm_hwenable(&spwmc->chip, pwm);
> +               }
> +       }
> +
> +       return 0;
> +}
> +#else
> +#define sirf_pwm_resume NULL
> +#define sirf_pwm_suspend NULL
> +#define sirf_pwm_restore NULL
> +#endif
> +
> +static const struct dev_pm_ops sirf_pwm_pm_ops = {
> +       .suspend = sirf_pwm_suspend,
> +       .resume = sirf_pwm_resume,
> +       .restore = sirf_pwm_restore,
> +};
> +
> +static const struct of_device_id sirf_pwm_of_match[] = {
> +       { .compatible = "sirf,prima2-pwm", },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, sirf_pwm_of_match);
> +
> +static struct platform_driver sirf_pwm_driver = {
> +       .driver = {
> +               .name = "sirf-pwm",
> +               .pm = &sirf_pwm_pm_ops,
> +               .of_match_table = sirf_pwm_of_match,
> +       },
> +       .probe = sirf_pwm_probe,
> +       .remove = sirf_pwm_remove,
> +};
> +module_platform_driver(sirf_pwm_driver);
> +
> +MODULE_DESCRIPTION("SIRF serial SoC PWM device core driver");
> +MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
> +MODULE_AUTHOR("Huayi Li <huayi.li@csr.com>");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.3

-barry

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks
  2014-07-16  1:55 ` [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks Huayi Li
@ 2014-07-24  9:53   ` Barry Song
  0 siblings, 0 replies; 7+ messages in thread
From: Barry Song @ 2014-07-24  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

2014-07-16 9:55 GMT+08:00 Huayi Li <huayi.li@csr.com>:
> This patch adds missed pwm-cells, clock-names and signal source
> clock for PWM module.
>
> Signed-off-by: Huayi Li <huayi.li@csr.com>

Reviewed-by: Barry Song <Baohua.Song@csr.com>

> ---
>  arch/arm/boot/dts/atlas6.dtsi | 8 ++++++--
>  arch/arm/boot/dts/prima2.dtsi | 8 ++++++--
>  2 files changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
> index bb22842..d424a69 100644
> --- a/arch/arm/boot/dts/atlas6.dtsi
> +++ b/arch/arm/boot/dts/atlas6.dtsi
> @@ -638,10 +638,14 @@
>                                  };
>                         };
>
> -                       pwm at b0130000 {
> +                       pwm: pwm at b0130000 {
>                                 compatible = "sirf,prima2-pwm";
> +                               #pwm-cells = <2>;
>                                 reg = <0xb0130000 0x10000>;
> -                               clocks = <&clks 21>;
> +                               clocks = <&clks 21>, <&clks 1>, <&clks 2>,
> +                                       <&clks 3>, <&clks 0>, <&clks 4>;
> +                               clock-names = "pwmc", "sigsrc0", "sigsrc1",
> +                                       "sigsrc2", "sigsrc3", "sigsrc4";
>                         };
>
>                         efusesys at b0140000 {
> diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
> index 963b7e5..68bb0c4 100644
> --- a/arch/arm/boot/dts/prima2.dtsi
> +++ b/arch/arm/boot/dts/prima2.dtsi
> @@ -646,10 +646,14 @@
>                                  };
>                         };
>
> -                       pwm at b0130000 {
> +                       pwm: pwm at b0130000 {
>                                 compatible = "sirf,prima2-pwm";
> +                               #pwm-cells = <2>;
>                                 reg = <0xb0130000 0x10000>;
> -                               clocks = <&clks 21>;
> +                               clocks = <&clks 21>, <&clks 1>, <&clks 2>,
> +                                       <&clks 3>, <&clks 0>, <&clks 4>;
> +                               clock-names = "pwmc", "sigsrc0", "sigsrc1",
> +                                       "sigsrc2", "sigsrc3", "sigsrc4";
>                         };
>
>                         efusesys at b0140000 {
> --
> 1.9.3
>

-barry

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-07-24  9:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-16  1:55 [PATCH v5 0/4] PWM: add and enable CSR SiRFSoC PWM driver Huayi Li
2014-07-16  1:55 ` [PATCH v5 1/4] pwm: add CSR SiRFSoc " Huayi Li
2014-07-24  9:48   ` Barry Song
2014-07-16  1:55 ` [PATCH v5 3/4] ARM: dts: sirf: fix the pwm-cells and clocks Huayi Li
2014-07-24  9:53   ` Barry Song
2014-07-16  1:55 ` [PATCH v5 4/4] ARM: prima2_defconfig: enable PWM and sirf PWM driver Huayi Li
2014-07-24  9:31   ` Barry Song

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).