All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tomasz Figa <t.figa@samsung.com>
To: linux-arm-kernel@lists.infradead.org
Cc: devicetree-discuss@lists.ozlabs.org,
	linux-samsung-soc@vger.kernel.org, kgene.kim@samsung.com,
	kyungmin.park@samsung.com, linux@simtec.co.uk,
	broonie@opensource.wolfsonmicro.com, kwangwoo.lee@gmail.com,
	jacmet@sunsite.dk, augulis.darius@gmail.com,
	mcuelenaere@gmail.com, linux@arm.linux.org.uk,
	sylvester.nawrocki@gmail.com, buserror@gmail.com,
	christer@weinigel.se, jekhor@gmail.com, ghcstop@gmail.com,
	mark.rutland@arm.com, tomasz.figa@gmail.com, heiko@sntech.de,
	robherring2@gmail.com, m.szyprowski@samsung.com, arnd@arndb.de,
	john.stultz@linaro.org, tglx@linutronix.de,
	Tomasz Figa <t.figa@samsung.com>
Subject: [PATCH v5 03/14] clocksource: samsung-pwm: Add infrastructure to share PWM hardware
Date: Fri, 12 Apr 2013 21:17:19 +0200	[thread overview]
Message-ID: <1365794250-14436-4-git-send-email-t.figa@samsung.com> (raw)
In-Reply-To: <1365794250-14436-1-git-send-email-t.figa@samsung.com>

This patch extends samsung PWM clocksource driver with infrastructure
that allows sharing of PWM hardware between clocksource and PWM drivers.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/pwm/pwm-samsung.txt        |  43 ++++
 drivers/clocksource/samsung_pwm.c                  | 250 +++++++++++++++++++++
 include/clocksource/samsung_pwm.h                  |  44 ++++
 3 files changed, 337 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-samsung.txt
 create mode 100644 include/clocksource/samsung_pwm.h

diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
new file mode 100644
index 0000000..cc17c4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
@@ -0,0 +1,43 @@
+* Samsung PWM timers
+
+Samsung SoCs contain PWM timer blocks which can be used for system clock source
+and clock event timers, as well as to drive SoC outputs with PWM signal. Each
+PWM timer block provides 5 PWM channels (not all of them can drive physical
+outputs - see SoC and board manual).
+
+Be aware that the clocksource driver supports only uniprocessor systems.
+
+Required properties:
+- compatible : should be one of following:
+    samsung,s3c2410-pwm - for 16-bit timers present on S3C24xx SoCs
+    samsung,s3c6400-pwm - for 32-bit timers present on S3C64xx SoCs
+    samsung,s5p6440-pwm - for 32-bit timers present on S5P64x0 SoCs
+    samsung,s5pc100-pwm - for 32-bit timers present on S5PC100, S5PV210,
+			  Exynos4210 rev0 SoCs
+    samsung,exynos4210-pwm - for 32-bit timers present on Exynos4210,
+                          Exynos4x12 and Exynos5250 SoCs
+- reg: base address and size of register area
+- interrupts: list of timer interrupts (one interrupt per timer, starting at
+  timer 0)
+- #pwm-cells: number of cells used for PWM specifier - must be 4
+   the specifier format is as follows:
+     - phandle to PWM controller node
+     - index of PWM channel (from 0 to 4)
+     - PWM signal period in nanoseconds
+     - bitmask of PWM flags:
+        0x1 - invert PWM signal
+
+Optional properties:
+- samsung,pwm-outputs: list of PWM channels used as PWM outputs on particular
+    platform - an array of up to 5 elements being indices of PWM channels
+    (from 0 to 4), the order does not matter.
+
+Example:
+	pwm@7f006000 {
+		compatible = "samsung,s3c6400-pwm";
+		reg = <0x7f006000 0x1000>;
+		interrupt-parent = <&vic0>;
+		interrupts = <23>, <24>, <25>, <27>, <28>;
+		samsung,pwm-outputs = <0>, <1>;
+		#pwm-cells = <2>;
+	}
diff --git a/drivers/clocksource/samsung_pwm.c b/drivers/clocksource/samsung_pwm.c
index 974675b..7bbd55c 100644
--- a/drivers/clocksource/samsung_pwm.c
+++ b/drivers/clocksource/samsung_pwm.c
@@ -14,7 +14,15 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <clocksource/samsung_pwm.h>
 
 #include <asm/smp_twd.h>
 #include <asm/mach/time.h>
@@ -27,6 +35,248 @@
 #include <plat/regs-timer.h>
 #include <plat/samsung-time.h>
 
+/*
+ * PWM master driver
+ */
+
+struct samsung_pwm_drvdata {
+	struct samsung_pwm pwm;
+	struct platform_device *pdev;
+	struct device_node *of_node;
+	struct resource resource;
+	struct list_head list;
+};
+
+static LIST_HEAD(pwm_list);
+
+#ifdef CONFIG_OF
+static int samsung_pwm_parse_dt(struct samsung_pwm_drvdata *drvdata)
+{
+	struct samsung_pwm *pwm = &drvdata->pwm;
+	struct samsung_pwm_variant *variant = &pwm->variant;
+	struct device_node *np = drvdata->of_node;
+	struct property *prop;
+	const __be32 *cur;
+	u32 val;
+	int i;
+
+	for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
+		pwm->irq[i] = irq_of_parse_and_map(np, i);
+
+	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;
+		}
+		variant->output_mask |= 1 << val;
+	}
+
+	return 0;
+}
+
+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 = &s5p_variant, },
+	{},
+};
+
+static struct samsung_pwm_drvdata *samsung_pwm_alloc(
+		struct platform_device *pdev, struct device_node *of_node,
+		const struct samsung_pwm_variant *variant)
+{
+	struct samsung_pwm_drvdata *drvdata;
+
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return NULL;
+
+	memcpy(&drvdata->pwm.variant, variant, sizeof(drvdata->pwm.variant));
+
+	spin_lock_init(&drvdata->pwm.slock);
+
+	drvdata->pdev = pdev;
+	drvdata->of_node = of_node;
+
+	return drvdata;
+}
+
+static struct samsung_pwm_drvdata *samsung_pwm_of_add(struct device_node *np)
+{
+	const struct samsung_pwm_variant *variant;
+	const struct of_device_id *match;
+	struct samsung_pwm_drvdata *pwm;
+	int ret;
+
+	if (!np) {
+		np = of_find_matching_node(NULL, samsung_pwm_matches);
+		if (!np) {
+			pr_err("%s: could not find PWM device\n", __func__);
+			return ERR_PTR(-ENODEV);
+		}
+	}
+
+	match = of_match_node(samsung_pwm_matches, np);
+	if (!match) {
+		pr_err("%s: failed to match given OF node\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+	variant = match->data;
+
+	pwm = samsung_pwm_alloc(NULL, np, variant);
+	if (!pwm) {
+		pr_err("%s: could not allocate PWM device struct\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = of_address_to_resource(np, 0, &pwm->resource);
+	if (ret < 0) {
+		pr_err("%s: could not get IO resource\n", __func__);
+		goto err_free;
+	}
+
+	ret = samsung_pwm_parse_dt(pwm);
+	if (ret < 0) {
+		pr_err("%s: failed to parse device tree node\n", __func__);
+		goto err_free;
+	}
+
+	list_add_tail(&pwm->list, &pwm_list);
+
+	return pwm;
+
+err_free:
+	kfree(pwm);
+
+	return ERR_PTR(ret);
+}
+#else
+static struct samsung_pwm_drvdata *samsung_pwm_of_add(struct device_node *np)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
+static struct samsung_pwm_drvdata *samsung_pwm_add(struct platform_device *pdev)
+{
+	struct samsung_pwm_variant *variant = pdev->dev.platform_data;
+	struct samsung_pwm_drvdata *pwm;
+	struct resource *res;
+	int i;
+
+	if (!variant) {
+		pr_err("%s: no platform data specified\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pwm = samsung_pwm_alloc(pdev, pdev->dev.of_node, variant);
+	if (!pwm) {
+		pr_err("%s: could not allocate PWM device struct\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("%s: could not get IO resource\n", __func__);
+		kfree(pwm);
+		return ERR_PTR(-EINVAL);
+	}
+	pwm->resource = *res;
+
+	for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
+		pwm->pwm.irq[i] = platform_get_irq(pdev, i);
+
+	list_add_tail(&pwm->list, &pwm_list);
+
+	return pwm;
+}
+
+static struct samsung_pwm_drvdata *samsung_pwm_find(
+			struct platform_device *pdev, struct device_node *np)
+{
+	struct samsung_pwm_drvdata *pwm;
+
+	if (pdev)
+		np = pdev->dev.of_node;
+
+	list_for_each_entry(pwm, &pwm_list, list)
+		if ((np && pwm->of_node == np) || !pdev || pwm->pdev == pdev)
+			return pwm;
+
+	if (pdev && !np)
+		return samsung_pwm_add(pdev);
+
+	return samsung_pwm_of_add(np);
+}
+
+struct samsung_pwm *samsung_pwm_get(struct platform_device *pdev,
+						struct device_node *of_node)
+{
+	struct samsung_pwm_drvdata *pwm;
+	struct resource *res;
+
+	pwm = samsung_pwm_find(pdev, of_node);
+	if (IS_ERR(pwm)) {
+		pr_err("%s: failed to instantiate PWM device\n", __func__);
+		return &pwm->pwm;
+	}
+
+	if (pwm->pwm.base)
+		return &pwm->pwm;
+
+	res = request_mem_region(pwm->resource.start,
+				resource_size(&pwm->resource), "samsung-pwm");
+	if (!res) {
+		pr_err("%s: failed to request IO mem region\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pwm->pwm.base = ioremap(res->start, resource_size(res));
+	if (!pwm->pwm.base) {
+		pr_err("%s: failed to map PWM registers\n", __func__);
+		release_mem_region(res->start, resource_size(res));
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return &pwm->pwm;
+}
+EXPORT_SYMBOL(samsung_pwm_get);
+
+/*
+ * Clocksource driver
+ */
+
 struct samsung_timer_source {
 	unsigned int event_id;
 	unsigned int source_id;
diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h
new file mode 100644
index 0000000..d16415f
--- /dev/null
+++ b/include/clocksource/samsung_pwm.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CLOCKSOURCE_SAMSUNG_PWM_H
+#define __CLOCKSOURCE_SAMSUNG_PWM_H
+
+#include <linux/spinlock.h>
+
+#define SAMSUNG_PWM_NUM		5
+
+struct platform_device;
+struct device_node;
+
+struct samsung_pwm_variant {
+	u8 bits;
+	u8 div_base;
+	u8 tclk_mask;
+	u8 output_mask;
+	bool has_tint_cstat;
+};
+
+struct samsung_pwm {
+	struct samsung_pwm_variant variant;
+	spinlock_t slock;
+	void __iomem *base;
+	int irq[SAMSUNG_PWM_NUM];
+};
+
+extern struct samsung_pwm *samsung_pwm_get(struct platform_device *,
+							struct device_node *);
+
+#endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */
-- 
1.8.1.5

WARNING: multiple messages have this Message-ID (diff)
From: t.figa@samsung.com (Tomasz Figa)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5 03/14] clocksource: samsung-pwm: Add infrastructure to share PWM hardware
Date: Fri, 12 Apr 2013 21:17:19 +0200	[thread overview]
Message-ID: <1365794250-14436-4-git-send-email-t.figa@samsung.com> (raw)
In-Reply-To: <1365794250-14436-1-git-send-email-t.figa@samsung.com>

This patch extends samsung PWM clocksource driver with infrastructure
that allows sharing of PWM hardware between clocksource and PWM drivers.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/pwm/pwm-samsung.txt        |  43 ++++
 drivers/clocksource/samsung_pwm.c                  | 250 +++++++++++++++++++++
 include/clocksource/samsung_pwm.h                  |  44 ++++
 3 files changed, 337 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-samsung.txt
 create mode 100644 include/clocksource/samsung_pwm.h

diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
new file mode 100644
index 0000000..cc17c4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
@@ -0,0 +1,43 @@
+* Samsung PWM timers
+
+Samsung SoCs contain PWM timer blocks which can be used for system clock source
+and clock event timers, as well as to drive SoC outputs with PWM signal. Each
+PWM timer block provides 5 PWM channels (not all of them can drive physical
+outputs - see SoC and board manual).
+
+Be aware that the clocksource driver supports only uniprocessor systems.
+
+Required properties:
+- compatible : should be one of following:
+    samsung,s3c2410-pwm - for 16-bit timers present on S3C24xx SoCs
+    samsung,s3c6400-pwm - for 32-bit timers present on S3C64xx SoCs
+    samsung,s5p6440-pwm - for 32-bit timers present on S5P64x0 SoCs
+    samsung,s5pc100-pwm - for 32-bit timers present on S5PC100, S5PV210,
+			  Exynos4210 rev0 SoCs
+    samsung,exynos4210-pwm - for 32-bit timers present on Exynos4210,
+                          Exynos4x12 and Exynos5250 SoCs
+- reg: base address and size of register area
+- interrupts: list of timer interrupts (one interrupt per timer, starting at
+  timer 0)
+- #pwm-cells: number of cells used for PWM specifier - must be 4
+   the specifier format is as follows:
+     - phandle to PWM controller node
+     - index of PWM channel (from 0 to 4)
+     - PWM signal period in nanoseconds
+     - bitmask of PWM flags:
+        0x1 - invert PWM signal
+
+Optional properties:
+- samsung,pwm-outputs: list of PWM channels used as PWM outputs on particular
+    platform - an array of up to 5 elements being indices of PWM channels
+    (from 0 to 4), the order does not matter.
+
+Example:
+	pwm at 7f006000 {
+		compatible = "samsung,s3c6400-pwm";
+		reg = <0x7f006000 0x1000>;
+		interrupt-parent = <&vic0>;
+		interrupts = <23>, <24>, <25>, <27>, <28>;
+		samsung,pwm-outputs = <0>, <1>;
+		#pwm-cells = <2>;
+	}
diff --git a/drivers/clocksource/samsung_pwm.c b/drivers/clocksource/samsung_pwm.c
index 974675b..7bbd55c 100644
--- a/drivers/clocksource/samsung_pwm.c
+++ b/drivers/clocksource/samsung_pwm.c
@@ -14,7 +14,15 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <clocksource/samsung_pwm.h>
 
 #include <asm/smp_twd.h>
 #include <asm/mach/time.h>
@@ -27,6 +35,248 @@
 #include <plat/regs-timer.h>
 #include <plat/samsung-time.h>
 
+/*
+ * PWM master driver
+ */
+
+struct samsung_pwm_drvdata {
+	struct samsung_pwm pwm;
+	struct platform_device *pdev;
+	struct device_node *of_node;
+	struct resource resource;
+	struct list_head list;
+};
+
+static LIST_HEAD(pwm_list);
+
+#ifdef CONFIG_OF
+static int samsung_pwm_parse_dt(struct samsung_pwm_drvdata *drvdata)
+{
+	struct samsung_pwm *pwm = &drvdata->pwm;
+	struct samsung_pwm_variant *variant = &pwm->variant;
+	struct device_node *np = drvdata->of_node;
+	struct property *prop;
+	const __be32 *cur;
+	u32 val;
+	int i;
+
+	for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
+		pwm->irq[i] = irq_of_parse_and_map(np, i);
+
+	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;
+		}
+		variant->output_mask |= 1 << val;
+	}
+
+	return 0;
+}
+
+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 = &s5p_variant, },
+	{},
+};
+
+static struct samsung_pwm_drvdata *samsung_pwm_alloc(
+		struct platform_device *pdev, struct device_node *of_node,
+		const struct samsung_pwm_variant *variant)
+{
+	struct samsung_pwm_drvdata *drvdata;
+
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return NULL;
+
+	memcpy(&drvdata->pwm.variant, variant, sizeof(drvdata->pwm.variant));
+
+	spin_lock_init(&drvdata->pwm.slock);
+
+	drvdata->pdev = pdev;
+	drvdata->of_node = of_node;
+
+	return drvdata;
+}
+
+static struct samsung_pwm_drvdata *samsung_pwm_of_add(struct device_node *np)
+{
+	const struct samsung_pwm_variant *variant;
+	const struct of_device_id *match;
+	struct samsung_pwm_drvdata *pwm;
+	int ret;
+
+	if (!np) {
+		np = of_find_matching_node(NULL, samsung_pwm_matches);
+		if (!np) {
+			pr_err("%s: could not find PWM device\n", __func__);
+			return ERR_PTR(-ENODEV);
+		}
+	}
+
+	match = of_match_node(samsung_pwm_matches, np);
+	if (!match) {
+		pr_err("%s: failed to match given OF node\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+	variant = match->data;
+
+	pwm = samsung_pwm_alloc(NULL, np, variant);
+	if (!pwm) {
+		pr_err("%s: could not allocate PWM device struct\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = of_address_to_resource(np, 0, &pwm->resource);
+	if (ret < 0) {
+		pr_err("%s: could not get IO resource\n", __func__);
+		goto err_free;
+	}
+
+	ret = samsung_pwm_parse_dt(pwm);
+	if (ret < 0) {
+		pr_err("%s: failed to parse device tree node\n", __func__);
+		goto err_free;
+	}
+
+	list_add_tail(&pwm->list, &pwm_list);
+
+	return pwm;
+
+err_free:
+	kfree(pwm);
+
+	return ERR_PTR(ret);
+}
+#else
+static struct samsung_pwm_drvdata *samsung_pwm_of_add(struct device_node *np)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
+static struct samsung_pwm_drvdata *samsung_pwm_add(struct platform_device *pdev)
+{
+	struct samsung_pwm_variant *variant = pdev->dev.platform_data;
+	struct samsung_pwm_drvdata *pwm;
+	struct resource *res;
+	int i;
+
+	if (!variant) {
+		pr_err("%s: no platform data specified\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pwm = samsung_pwm_alloc(pdev, pdev->dev.of_node, variant);
+	if (!pwm) {
+		pr_err("%s: could not allocate PWM device struct\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("%s: could not get IO resource\n", __func__);
+		kfree(pwm);
+		return ERR_PTR(-EINVAL);
+	}
+	pwm->resource = *res;
+
+	for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
+		pwm->pwm.irq[i] = platform_get_irq(pdev, i);
+
+	list_add_tail(&pwm->list, &pwm_list);
+
+	return pwm;
+}
+
+static struct samsung_pwm_drvdata *samsung_pwm_find(
+			struct platform_device *pdev, struct device_node *np)
+{
+	struct samsung_pwm_drvdata *pwm;
+
+	if (pdev)
+		np = pdev->dev.of_node;
+
+	list_for_each_entry(pwm, &pwm_list, list)
+		if ((np && pwm->of_node == np) || !pdev || pwm->pdev == pdev)
+			return pwm;
+
+	if (pdev && !np)
+		return samsung_pwm_add(pdev);
+
+	return samsung_pwm_of_add(np);
+}
+
+struct samsung_pwm *samsung_pwm_get(struct platform_device *pdev,
+						struct device_node *of_node)
+{
+	struct samsung_pwm_drvdata *pwm;
+	struct resource *res;
+
+	pwm = samsung_pwm_find(pdev, of_node);
+	if (IS_ERR(pwm)) {
+		pr_err("%s: failed to instantiate PWM device\n", __func__);
+		return &pwm->pwm;
+	}
+
+	if (pwm->pwm.base)
+		return &pwm->pwm;
+
+	res = request_mem_region(pwm->resource.start,
+				resource_size(&pwm->resource), "samsung-pwm");
+	if (!res) {
+		pr_err("%s: failed to request IO mem region\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pwm->pwm.base = ioremap(res->start, resource_size(res));
+	if (!pwm->pwm.base) {
+		pr_err("%s: failed to map PWM registers\n", __func__);
+		release_mem_region(res->start, resource_size(res));
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return &pwm->pwm;
+}
+EXPORT_SYMBOL(samsung_pwm_get);
+
+/*
+ * Clocksource driver
+ */
+
 struct samsung_timer_source {
 	unsigned int event_id;
 	unsigned int source_id;
diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h
new file mode 100644
index 0000000..d16415f
--- /dev/null
+++ b/include/clocksource/samsung_pwm.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CLOCKSOURCE_SAMSUNG_PWM_H
+#define __CLOCKSOURCE_SAMSUNG_PWM_H
+
+#include <linux/spinlock.h>
+
+#define SAMSUNG_PWM_NUM		5
+
+struct platform_device;
+struct device_node;
+
+struct samsung_pwm_variant {
+	u8 bits;
+	u8 div_base;
+	u8 tclk_mask;
+	u8 output_mask;
+	bool has_tint_cstat;
+};
+
+struct samsung_pwm {
+	struct samsung_pwm_variant variant;
+	spinlock_t slock;
+	void __iomem *base;
+	int irq[SAMSUNG_PWM_NUM];
+};
+
+extern struct samsung_pwm *samsung_pwm_get(struct platform_device *,
+							struct device_node *);
+
+#endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */
-- 
1.8.1.5

  parent reply	other threads:[~2013-04-12 19:17 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-12 19:17 [PATCH v5 00/14] ARM: samsung-time: Prepare for multiplatform support Tomasz Figa
2013-04-12 19:17 ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 01/14] ARM: SAMSUNG: Move samsung-time to drivers/clocksource Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
     [not found]   ` <1365794250-14436-2-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-04-12 20:44     ` Arnd Bergmann
2013-04-12 20:44       ` Arnd Bergmann
2013-04-12 20:52       ` Tomasz Figa
2013-04-12 20:52         ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 02/14] clocksource: samsung-pwm: Clean up platform header Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` Tomasz Figa [this message]
2013-04-12 19:17   ` [PATCH v5 03/14] clocksource: samsung-pwm: Add infrastructure to share PWM hardware Tomasz Figa
2013-04-12 20:42   ` Arnd Bergmann
2013-04-12 20:42     ` Arnd Bergmann
2013-04-12 20:47     ` Tomasz Figa
2013-04-12 20:47       ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 04/14] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 05/14] ARM: SAMSUNG: Add new PWM platform device Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 06/14] ARM: SAMSUNG: Set PWM platform data Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 07/14] clocksource: samsung-pwm: Use platform data to setup the clocksource Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 08/14] clocksource: samsung-pwm: Synchronize register accesses Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 09/14] clocksource: samsung-pwm: Move IRQ mask/ack handling to the driver Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 10/14] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 11/14] clocksource: samsung-pwm: Configure dividers directly Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 12/14] clocksource: samsung-pwm: Do not use static mapping of registers Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 13/14] clocksource: samsung-pwm: Drop unnecessary includes Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 19:17 ` [PATCH v5 14/14] clocksource: samsung-pwm: Prepare for clocksource_of_init Tomasz Figa
2013-04-12 19:17   ` Tomasz Figa
2013-04-12 20:51 ` [PATCH v5 00/14] ARM: samsung-time: Prepare for multiplatform support Arnd Bergmann
2013-04-12 20:51   ` Arnd Bergmann
2013-04-22 17:37   ` Kukjin Kim
2013-04-22 17:37     ` Kukjin Kim
2013-04-22 19:21     ` Tomasz Figa
2013-04-22 19:21       ` Tomasz Figa
2013-04-12 22:22 ` Heiko Stübner
2013-04-12 22:22   ` Heiko Stübner
2013-04-12 22:26   ` Arnd Bergmann
2013-04-12 22:26     ` Arnd Bergmann
2013-04-12 22:39     ` Heiko Stübner
2013-04-12 22:39       ` Heiko Stübner
2013-04-12 22:42       ` Tomasz Figa
2013-04-12 22:42         ` Tomasz Figa
2013-04-13 12:28 ` Tomasz Figa
2013-04-13 12:28   ` Tomasz Figa
2013-04-16 16:22 ` Mark Brown
2013-04-16 16:22   ` Mark Brown
2013-04-16 20:51 ` Sylwester Nawrocki
2013-04-16 20:51   ` Sylwester Nawrocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1365794250-14436-4-git-send-email-t.figa@samsung.com \
    --to=t.figa@samsung.com \
    --cc=arnd@arndb.de \
    --cc=augulis.darius@gmail.com \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=buserror@gmail.com \
    --cc=christer@weinigel.se \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=ghcstop@gmail.com \
    --cc=heiko@sntech.de \
    --cc=jacmet@sunsite.dk \
    --cc=jekhor@gmail.com \
    --cc=john.stultz@linaro.org \
    --cc=kgene.kim@samsung.com \
    --cc=kwangwoo.lee@gmail.com \
    --cc=kyungmin.park@samsung.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=linux@simtec.co.uk \
    --cc=m.szyprowski@samsung.com \
    --cc=mark.rutland@arm.com \
    --cc=mcuelenaere@gmail.com \
    --cc=robherring2@gmail.com \
    --cc=sylvester.nawrocki@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=tomasz.figa@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.