2012-11-20 05:11:39

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 00/10] Support for AM33xx PWM Subsystem

In AM33xx PWM sub modules like ECAP, EHRPWM & EQEP are integrated to
PWM subsystem. All these submodules shares the resources (clock) & has
a clock gating register in PWM Subsystem. This patch series creates a
parent PWM Subsystem driver to handle access synchronization of shared
resources & clock gating from PWM Subsystem configuration space.
Also Device tree nodes populated to support parent child relation
between PWMSS, ECAP & EHRPWM submodules.
In addition EHRPWM module requires explicit clock gating from control
module & is handled by patch #2 & 8.

Patch #4 & 6 submitted is a second revision as suggested by Thierry
for handling clock gating with a global function . This requires config
space handling done independent from driver and is done at parent driver.
So the parent<->child relation adopted to handle
1. pm runtime synchronization
2. PWM subsystem common config space clock gating for PWM submodules.

Patches supports
- Driver support for parent child relation handled patch #1
- Optional EHRPWM tb clock in patch #2
- Parent child in HWMOD handled at patch #3
- Device tree binding support handled in patch #4, 6 &8
- pinctrl support in patch #5 & 7.
- DT node populated in patch #9 & 10.

This patch series based on linux-next/20121115 and tested on AM33xx.
It depends on [1]

1. https://lkml.org/lkml/2012/11/19/338
pwm: Device tree support for PWM polarity

Philip, Avinash (10):
PWMSS: Add PWM Subsystem driver for parent<->child relationship
ARM: am33xx: clk: Add optional clock for EHRPWM
ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM
subsystem
pwm: pwm-tiecap: Add device-tree binding support for APWM driver
pwm: pwm-tiecap: pinctrl support
pwm: pwm-tiehrpwm: Add device-tree binding support for EHRPWM driver
pwm: pwm-tiehrpwm: pinctrl support
pwm: pwm-tiehrpwm: Adding TBCLK gating support.
ARM: dts: AM33XX: Add PWMSS device tree nodes
ARM: dts: AM33XX: Add PWM backlight DT data to am335x-evm

.../devicetree/bindings/pwm/pwm-tiecap.txt | 23 ++
.../devicetree/bindings/pwm/pwm-tiehrpwm.txt | 23 ++
.../devicetree/bindings/pwm/pwm-tipwmss.txt | 32 ++
arch/arm/boot/dts/am335x-evm.dts | 21 +
arch/arm/boot/dts/am33xx.dtsi | 84 ++++
arch/arm/mach-omap2/clock33xx_data.c | 37 ++
arch/arm/mach-omap2/control.h | 8 +
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 419 +++++++++++++-------
drivers/pwm/Kconfig | 11 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-tiecap.c | 50 +++-
drivers/pwm/pwm-tiehrpwm.c | 65 +++-
drivers/pwm/pwm-tipwmss.c | 143 +++++++
drivers/pwm/tipwmss.h | 39 ++
14 files changed, 811 insertions(+), 145 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
create mode 100644 drivers/pwm/pwm-tipwmss.c
create mode 100644 drivers/pwm/tipwmss.h


2012-11-20 05:11:52

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 02/10] ARM: am33xx: clk: Add optional clock for EHRPWM

EHRPWM module requires explicit clock gating from control module.
Hence add clock node in clock tree for EHRPWM modules.

Signed-off-by: Philip, Avinash <[email protected]>
---
:100644 100644 17e3de5... 833260f... M arch/arm/mach-omap2/clock33xx_data.c
:100644 100644 a89e825... c0e34e6... M arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/clock33xx_data.c | 37 ++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/control.h | 8 +++++++
2 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
index 17e3de5..833260f 100644
--- a/arch/arm/mach-omap2/clock33xx_data.c
+++ b/arch/arm/mach-omap2/clock33xx_data.c
@@ -995,6 +995,40 @@ static struct clk wdt1_fck = {
};

/*
+ * PWMSS Time based module clock node. This node is
+ * requred to enable clock gating for EHRPWM TBCLK.
+ */
+static struct clk ehrpwm0_tbclk = {
+ .name = "ehrpwm0_tbclk",
+ .clkdm_name = "l4ls_clkdm",
+ .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
+ .enable_bit = AM33XX_PWMSS0_TBCLKEN_SHIFT,
+ .ops = &clkops_omap2_dflt,
+ .parent = &l4ls_gclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk ehrpwm1_tbclk = {
+ .name = "ehrpwm1_tbclk",
+ .clkdm_name = "l4ls_clkdm",
+ .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
+ .enable_bit = AM33XX_PWMSS1_TBCLKEN_SHIFT,
+ .ops = &clkops_omap2_dflt,
+ .parent = &l4ls_gclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk ehrpwm2_tbclk = {
+ .name = "ehrpwm2_tbclk",
+ .clkdm_name = "l4ls_clkdm",
+ .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
+ .enable_bit = AM33XX_PWMSS2_TBCLKEN_SHIFT,
+ .ops = &clkops_omap2_dflt,
+ .parent = &l4ls_gclk,
+ .recalc = &followparent_recalc,
+};
+
+/*
* clkdev
*/
static struct omap_clk am33xx_clks[] = {
@@ -1074,6 +1108,9 @@ static struct omap_clk am33xx_clks[] = {
CLK(NULL, "clkout2_ck", &clkout2_ck, CK_AM33XX),
CLK(NULL, "timer_32k_ck", &clkdiv32k_ick, CK_AM33XX),
CLK(NULL, "timer_sys_ck", &sys_clkin_ck, CK_AM33XX),
+ CLK(NULL, "ehrpwm0_tbclk", &ehrpwm0_tbclk, CK_AM33XX),
+ CLK(NULL, "ehrpwm1_tbclk", &ehrpwm1_tbclk, CK_AM33XX),
+ CLK(NULL, "ehrpwm2_tbclk", &ehrpwm2_tbclk, CK_AM33XX),
};

int __init am33xx_clk_init(void)
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index a89e825..c0e34e6 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -357,6 +357,14 @@
#define AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH 0x2
#define AM33XX_CONTROL_STATUS_SYSBOOT1_MASK (0x3 << 22)

+/* AM33XX PWMSS Control register */
+#define AM33XX_PWMSS_TBCLK_CLKCTRL 0x664
+
+/* AM33XX PWMSS Control bitfields */
+#define AM33XX_PWMSS0_TBCLKEN_SHIFT 0
+#define AM33XX_PWMSS1_TBCLKEN_SHIFT 1
+#define AM33XX_PWMSS2_TBCLKEN_SHIFT 2
+
/* CONTROL OMAP STATUS register to identify OMAP3 features */
#define OMAP3_CONTROL_OMAP_STATUS 0x044c

--
1.7.0.4

2012-11-20 05:12:00

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

As part of PWM subsystem integration, PWM subsystem are sharing
resources like clock across submodules (ECAP, EQEP & EHRPWM).
To handle resource sharing & IP integration
1. Rework on parent child relation between PWMSS and
ECAP, EQEP & EHRPWM child devices to support runtime PM.
2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
clock gating from control module.
3. Add HWMOD entries for EQEP PWM submodule.

Signed-off-by: Philip, Avinash <[email protected]>
---
Changes since v1:
- Remove ADDR_TYPE_RT for PWM sub module register entries.

:100644 100644 ad8d43b... de2301c... M arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 419 ++++++++++++++++++----------
1 files changed, 276 insertions(+), 143 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index ad8d43b..de2301c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -768,9 +768,7 @@ static struct omap_hwmod am33xx_elm_hwmod = {
},
};

-/*
- * 'epwmss' class: ecap0,1,2, ehrpwm0,1,2
- */
+/* pwmss */
static struct omap_hwmod_class_sysconfig am33xx_epwmss_sysc = {
.rev_offs = 0x0,
.sysc_offs = 0x4,
@@ -786,18 +784,23 @@ static struct omap_hwmod_class am33xx_epwmss_hwmod_class = {
.sysc = &am33xx_epwmss_sysc,
};

-/* ehrpwm0 */
-static struct omap_hwmod_irq_info am33xx_ehrpwm0_irqs[] = {
- { .name = "int", .irq = 86 + OMAP_INTC_START, },
- { .name = "tzint", .irq = 58 + OMAP_INTC_START, },
- { .irq = -1 },
+
+static struct omap_hwmod_class am33xx_ecap_hwmod_class = {
+ .name = "ecap",
};

-static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
- .name = "ehrpwm0",
+static struct omap_hwmod_class am33xx_eqep_hwmod_class = {
+ .name = "eqep",
+};
+
+static struct omap_hwmod_class am33xx_ehrpwm_hwmod_class = {
+ .name = "ehrpwm",
+};
+/* epwmss0 */
+static struct omap_hwmod am33xx_epwmss0_hwmod = {
+ .name = "epwmss0",
.class = &am33xx_epwmss_hwmod_class,
.clkdm_name = "l4ls_clkdm",
- .mpu_irqs = am33xx_ehrpwm0_irqs,
.main_clk = "l4ls_gclk",
.prcm = {
.omap4 = {
@@ -807,63 +810,68 @@ static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
},
};

-/* ehrpwm1 */
-static struct omap_hwmod_irq_info am33xx_ehrpwm1_irqs[] = {
- { .name = "int", .irq = 87 + OMAP_INTC_START, },
- { .name = "tzint", .irq = 59 + OMAP_INTC_START, },
+/* ecap0 */
+static struct omap_hwmod_irq_info am33xx_ecap0_irqs[] = {
+ { .irq = 31 + OMAP_INTC_START, },
{ .irq = -1 },
};

-static struct omap_hwmod am33xx_ehrpwm1_hwmod = {
- .name = "ehrpwm1",
- .class = &am33xx_epwmss_hwmod_class,
+static struct omap_hwmod am33xx_ecap0_hwmod = {
+ .name = "ecap0",
+ .class = &am33xx_ecap_hwmod_class,
.clkdm_name = "l4ls_clkdm",
- .mpu_irqs = am33xx_ehrpwm1_irqs,
+ .mpu_irqs = am33xx_ecap0_irqs,
.main_clk = "l4ls_gclk",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
- .modulemode = MODULEMODE_SWCTRL,
- },
- },
};

-/* ehrpwm2 */
-static struct omap_hwmod_irq_info am33xx_ehrpwm2_irqs[] = {
- { .name = "int", .irq = 39 + OMAP_INTC_START, },
- { .name = "tzint", .irq = 60 + OMAP_INTC_START, },
+/* eqep0 */
+static struct omap_hwmod_irq_info am33xx_eqep0_irqs[] = {
+ { .irq = 79 + OMAP_INTC_START, },
{ .irq = -1 },
};

-static struct omap_hwmod am33xx_ehrpwm2_hwmod = {
- .name = "ehrpwm2",
- .class = &am33xx_epwmss_hwmod_class,
+static struct omap_hwmod am33xx_eqep0_hwmod = {
+ .name = "eqep0",
+ .class = &am33xx_eqep_hwmod_class,
.clkdm_name = "l4ls_clkdm",
- .mpu_irqs = am33xx_ehrpwm2_irqs,
+ .mpu_irqs = am33xx_eqep0_irqs,
.main_clk = "l4ls_gclk",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
- .modulemode = MODULEMODE_SWCTRL,
- },
- },
};

-/* ecap0 */
-static struct omap_hwmod_irq_info am33xx_ecap0_irqs[] = {
- { .irq = 31 + OMAP_INTC_START, },
+/* ehrpwm0 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm0_irqs[] = {
+ { .name = "int", .irq = 86 + OMAP_INTC_START, },
+ { .name = "tzint", .irq = 58 + OMAP_INTC_START, },
{ .irq = -1 },
};

-static struct omap_hwmod am33xx_ecap0_hwmod = {
- .name = "ecap0",
+/*
+ * Optional clock entry is provided to support additional clock
+ * gating for EHRPWM module functional from control module.
+ */
+static struct omap_hwmod_opt_clk ehrpwm0_opt_clks[] = {
+ { .role = "tbclk", .clk = "ehrpwm0_tbclk" },
+};
+
+static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
+ .name = "ehrpwm0",
+ .class = &am33xx_ehrpwm_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
+ .mpu_irqs = am33xx_ehrpwm0_irqs,
+ .main_clk = "l4ls_gclk",
+ .opt_clks = ehrpwm0_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(ehrpwm0_opt_clks),
+};
+
+/* epwmss1 */
+static struct omap_hwmod am33xx_epwmss1_hwmod = {
+ .name = "epwmss1",
.class = &am33xx_epwmss_hwmod_class,
.clkdm_name = "l4ls_clkdm",
- .mpu_irqs = am33xx_ecap0_irqs,
.main_clk = "l4ls_gclk",
.prcm = {
.omap4 = {
- .clkctrl_offs = AM33XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET,
+ .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
@@ -877,13 +885,60 @@ static struct omap_hwmod_irq_info am33xx_ecap1_irqs[] = {

static struct omap_hwmod am33xx_ecap1_hwmod = {
.name = "ecap1",
- .class = &am33xx_epwmss_hwmod_class,
+ .class = &am33xx_ecap_hwmod_class,
.clkdm_name = "l4ls_clkdm",
.mpu_irqs = am33xx_ecap1_irqs,
.main_clk = "l4ls_gclk",
+};
+
+/* eqep1 */
+static struct omap_hwmod_irq_info am33xx_eqep1_irqs[] = {
+ { .irq = 88 + OMAP_INTC_START, },
+ { .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_eqep1_hwmod = {
+ .name = "eqep1",
+ .class = &am33xx_eqep_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
+ .mpu_irqs = am33xx_eqep1_irqs,
+ .main_clk = "l4ls_gclk",
+};
+
+/* ehrpwm1 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm1_irqs[] = {
+ { .name = "int", .irq = 87 + OMAP_INTC_START, },
+ { .name = "tzint", .irq = 59 + OMAP_INTC_START, },
+ { .irq = -1 },
+};
+
+/*
+ * Optional clock entry is provided to support additional clock
+ * gating for EHRPWM module functional from control module.
+ */
+static struct omap_hwmod_opt_clk ehrpwm1_opt_clks[] = {
+ { .role = "tbclk", .clk = "ehrpwm1_tbclk" },
+};
+
+static struct omap_hwmod am33xx_ehrpwm1_hwmod = {
+ .name = "ehrpwm1",
+ .class = &am33xx_ehrpwm_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
+ .mpu_irqs = am33xx_ehrpwm1_irqs,
+ .main_clk = "l4ls_gclk",
+ .opt_clks = ehrpwm1_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(ehrpwm1_opt_clks),
+};
+
+/* epwmss2 */
+static struct omap_hwmod am33xx_epwmss2_hwmod = {
+ .name = "epwmss2",
+ .class = &am33xx_epwmss_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
+ .main_clk = "l4ls_gclk",
.prcm = {
.omap4 = {
- .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
+ .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
@@ -897,16 +952,49 @@ static struct omap_hwmod_irq_info am33xx_ecap2_irqs[] = {

static struct omap_hwmod am33xx_ecap2_hwmod = {
.name = "ecap2",
+ .class = &am33xx_ecap_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
.mpu_irqs = am33xx_ecap2_irqs,
- .class = &am33xx_epwmss_hwmod_class,
+ .main_clk = "l4ls_gclk",
+};
+
+/* eqep2 */
+static struct omap_hwmod_irq_info am33xx_eqep2_irqs[] = {
+ { .irq = 89 + OMAP_INTC_START, },
+ { .irq = -1 },
+};
+
+static struct omap_hwmod am33xx_eqep2_hwmod = {
+ .name = "eqep2",
+ .class = &am33xx_eqep_hwmod_class,
.clkdm_name = "l4ls_clkdm",
+ .mpu_irqs = am33xx_eqep2_irqs,
.main_clk = "l4ls_gclk",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
- .modulemode = MODULEMODE_SWCTRL,
- },
- },
+};
+
+/* ehrpwm2 */
+static struct omap_hwmod_irq_info am33xx_ehrpwm2_irqs[] = {
+ { .name = "int", .irq = 39 + OMAP_INTC_START, },
+ { .name = "tzint", .irq = 60 + OMAP_INTC_START, },
+ { .irq = -1 },
+};
+
+/*
+ * Optional clock entry is provided to support additional clock
+ * gating for EHRPWM module functional from control module.
+ */
+static struct omap_hwmod_opt_clk ehrpwm2_opt_clks[] = {
+ { .role = "tbclk", .clk = "ehrpwm2_tbclk" },
+};
+
+static struct omap_hwmod am33xx_ehrpwm2_hwmod = {
+ .name = "ehrpwm2",
+ .class = &am33xx_ehrpwm_hwmod_class,
+ .clkdm_name = "l4ls_clkdm",
+ .mpu_irqs = am33xx_ehrpwm2_irqs,
+ .main_clk = "l4ls_gclk",
+ .opt_clks = ehrpwm2_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(ehrpwm2_opt_clks),
};

/*
@@ -2518,162 +2606,201 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = {
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_epwmss0_addr_space[] = {
{
.pa_start = 0x48300000,
.pa_end = 0x48300000 + SZ_16 - 1,
.flags = ADDR_TYPE_RT
},
- {
- .pa_start = 0x48300200,
- .pa_end = 0x48300200 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
- },
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm0 = {
+static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss0 = {
.master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ehrpwm0_hwmod,
+ .slave = &am33xx_epwmss0_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ehrpwm0_addr_space,
+ .addr = am33xx_epwmss0_addr_space,
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = {
- {
- .pa_start = 0x48302000,
- .pa_end = 0x48302000 + SZ_16 - 1,
- .flags = ADDR_TYPE_RT
- },
+static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
{
- .pa_start = 0x48302200,
- .pa_end = 0x48302200 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
+ .pa_start = 0x48300100,
+ .pa_end = 0x48300100 + SZ_128 - 1,
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm1 = {
- .master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ehrpwm1_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss0__ecap0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_ecap0_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ehrpwm1_addr_space,
+ .addr = am33xx_ecap0_addr_space,
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_eqep0_addr_space[] = {
{
- .pa_start = 0x48304000,
- .pa_end = 0x48304000 + SZ_16 - 1,
- .flags = ADDR_TYPE_RT
- },
- {
- .pa_start = 0x48304200,
- .pa_end = 0x48304200 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
+ .pa_start = 0x48300180,
+ .pa_end = 0x48300180 + SZ_128 - 1,
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm2 = {
- .master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ehrpwm2_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss0__eqep0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_eqep0_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ehrpwm2_addr_space,
+ .addr = am33xx_eqep0_addr_space,
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
- {
- .pa_start = 0x48300000,
- .pa_end = 0x48300000 + SZ_16 - 1,
- .flags = ADDR_TYPE_RT
- },
+static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
{
- .pa_start = 0x48300100,
- .pa_end = 0x48300100 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
+ .pa_start = 0x48300200,
+ .pa_end = 0x48300200 + SZ_128 - 1,
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap0 = {
- .master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ecap0_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss0__ehrpwm0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_ehrpwm0_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ecap0_addr_space,
+ .addr = am33xx_ehrpwm0_addr_space,
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_epwmss1_addr_space[] = {
{
.pa_start = 0x48302000,
.pa_end = 0x48302000 + SZ_16 - 1,
.flags = ADDR_TYPE_RT
},
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss1 = {
+ .master = &am33xx_l4_ls_hwmod,
+ .slave = &am33xx_epwmss1_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_epwmss1_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = {
{
.pa_start = 0x48302100,
- .pa_end = 0x48302100 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
+ .pa_end = 0x48302100 + SZ_128 - 1,
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap1 = {
- .master = &am33xx_l4_ls_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss1__ecap1 = {
+ .master = &am33xx_epwmss1_hwmod,
.slave = &am33xx_ecap1_hwmod,
.clk = "l4ls_gclk",
.addr = am33xx_ecap1_addr_space,
.user = OCP_USER_MPU,
};

-/*
- * Splitting the resources to handle access of PWMSS config space
- * and module specific part independently
- */
-static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_eqep1_addr_space[] = {
+ {
+ .pa_start = 0x48302180,
+ .pa_end = 0x48302180 + SZ_128 - 1,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss1__eqep1 = {
+ .master = &am33xx_epwmss1_hwmod,
+ .slave = &am33xx_eqep1_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_eqep1_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = {
+ {
+ .pa_start = 0x48302200,
+ .pa_end = 0x48302200 + SZ_128 - 1,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss1__ehrpwm1 = {
+ .master = &am33xx_epwmss1_hwmod,
+ .slave = &am33xx_ehrpwm1_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_ehrpwm1_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_epwmss2_addr_space[] = {
{
.pa_start = 0x48304000,
.pa_end = 0x48304000 + SZ_16 - 1,
.flags = ADDR_TYPE_RT
},
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss2 = {
+ .master = &am33xx_l4_ls_hwmod,
+ .slave = &am33xx_epwmss2_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_epwmss2_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = {
{
.pa_start = 0x48304100,
- .pa_end = 0x48304100 + SZ_256 - 1,
- .flags = ADDR_TYPE_RT
+ .pa_end = 0x48304100 + SZ_128 - 1,
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap2 = {
- .master = &am33xx_l4_ls_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss2__ecap2 = {
+ .master = &am33xx_epwmss2_hwmod,
.slave = &am33xx_ecap2_hwmod,
.clk = "l4ls_gclk",
.addr = am33xx_ecap2_addr_space,
.user = OCP_USER_MPU,
};

+static struct omap_hwmod_addr_space am33xx_eqep2_addr_space[] = {
+ {
+ .pa_start = 0x48304180,
+ .pa_end = 0x48304180 + SZ_128 - 1,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss2__eqep2 = {
+ .master = &am33xx_epwmss2_hwmod,
+ .slave = &am33xx_eqep2_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_eqep2_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = {
+ {
+ .pa_start = 0x48304200,
+ .pa_end = 0x48304200 + SZ_128 - 1,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss2__ehrpwm2 = {
+ .master = &am33xx_epwmss2_hwmod,
+ .slave = &am33xx_ehrpwm2_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_ehrpwm2_addr_space,
+ .user = OCP_USER_MPU,
+};
+
/* l3s cfg -> gpmc */
static struct omap_hwmod_addr_space am33xx_gpmc_addr_space[] = {
{
@@ -3356,12 +3483,18 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
&am33xx_l4_ls__uart6,
&am33xx_l4_ls__spinlock,
&am33xx_l4_ls__elm,
- &am33xx_l4_ls__ehrpwm0,
- &am33xx_l4_ls__ehrpwm1,
- &am33xx_l4_ls__ehrpwm2,
- &am33xx_l4_ls__ecap0,
- &am33xx_l4_ls__ecap1,
- &am33xx_l4_ls__ecap2,
+ &am33xx_l4_ls__epwmss0,
+ &am33xx_epwmss0__ecap0,
+ &am33xx_epwmss0__eqep0,
+ &am33xx_epwmss0__ehrpwm0,
+ &am33xx_l4_ls__epwmss1,
+ &am33xx_epwmss1__ecap1,
+ &am33xx_epwmss1__eqep1,
+ &am33xx_epwmss1__ehrpwm1,
+ &am33xx_l4_ls__epwmss2,
+ &am33xx_epwmss2__ecap2,
+ &am33xx_epwmss2__eqep2,
+ &am33xx_epwmss2__ehrpwm2,
&am33xx_l3_s__gpmc,
&am33xx_l3_main__lcdc,
&am33xx_l4_ls__mcspi0,
--
1.7.0.4

2012-11-20 05:11:49

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 01/10] PWMSS: Add PWM Subsystem driver for parent<->child relationship

In some platforms (like am33xx), PWM sub modules (ECAP, EHRPWM, EQEP)
are integrated to PWM subsystem. These PWM submodules has resources
shared and only one register bit-field is provided to control
module/clock enable/disable, makes it difficult to handle common
resources from independent PWMSS submodule drivers.

So the solution here implemented in this patch is, to create driver for
PWMSS and take the role of parent driver for PWM submodules. PWMSS
parent driver enumerates all the child nodes under PWMSS module. Also
symbol "pwmss_submodule_state_change" exported to enable clock gating
for individual PWMSS submodules, and submodule drivers has to enable
clock gating from their drivers.

As this is only supported during DT boot, the parent<->child relationship
is created and populated in DT execution flow. The only required change
is inside DTS file, making EHRPWM & ECAP as a child to PWMSS node.

Signed-off-by: Philip, Avinash <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
---
Changes since v2:
- Corrected the usage of ranges property in documentation.
- Set build attribute to bool type.
- Add pwm prefix to tipwmss.c file
- Span mutex protection for read modify approach.
- Use SET_SYSTEM_SLEEP_PM_OPS
- Add PWM subsystem bit fields to tipwmss.h
- Remove devinit & devexit attributes.
- Left out adding of child node's DT property in Documentation
as those definitions are part of later patches.

Changes since v1:
- Add conditional check for PWM subsystem clock enabling.
- Add context save/restore for PWM subsystem clock config register.

:000000 100644 0000000... 4906a85... A Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
:100644 100644 6e556c7... 3dcb76d... M drivers/pwm/Kconfig
:100644 100644 3b3f4c9a.. 4fb39f8... M drivers/pwm/Makefile
:000000 100644 0000000... 133635c... A drivers/pwm/pwm-tipwmss.c
:000000 100644 0000000... 11f76a1... A drivers/pwm/tipwmss.h
.../devicetree/bindings/pwm/pwm-tipwmss.txt | 32 +++++
drivers/pwm/Kconfig | 11 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-tipwmss.c | 143 ++++++++++++++++++++
drivers/pwm/tipwmss.h | 39 ++++++
5 files changed, 226 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
new file mode 100644
index 0000000..4906a85
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
@@ -0,0 +1,32 @@
+TI SOC based PWM Subsystem
+
+Required properties:
+- compatible: Must be "ti,am33xx-pwmss";
+- reg: physical base address and size of the registers map.
+- address-cells: Specify the number of u32 entries needed in child nodes.
+ Should set to 1.
+- size-cells: specify number of u32 entries needed to specify child nodes size
+ in reg property. Should set to 1.
+- ranges: describes the address mapping of a memory-mapped bus. Should set to
+ physical address map of child's base address, physical address within
+ parent's address space and length of the address map. For am33xx,
+ 3 set of child register maps present, ECAP register space, EQEP
+ register space, EHRPWM register space.
+
+Also child nodes should also populated under PWMSS DT node.
+
+Example:
+pwmss0: pwmss@48300000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48300000 0x10
+ 0x48300100 0x80
+ 0x48300180 0x80
+ 0x48300200 0x80>;
+ ti,hwmods = "epwmss0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges;
+
+ /* child nodes go here */
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6e556c7..3dcb76d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -136,6 +136,7 @@ config PWM_TEGRA
config PWM_TIECAP
tristate "ECAP PWM support"
depends on SOC_AM33XX
+ select PWM_TIPWMSS
help
PWM driver support for the ECAP APWM controller found on AM33XX
TI SOC
@@ -146,6 +147,7 @@ config PWM_TIECAP
config PWM_TIEHRPWM
tristate "EHRPWM PWM support"
depends on SOC_AM33XX
+ select PWM_TIPWMSS
help
PWM driver support for the EHRPWM controller found on AM33XX
TI SOC
@@ -153,6 +155,15 @@ config PWM_TIEHRPWM
To compile this driver as a module, choose M here: the module
will be called pwm-tiehrpwm.

+config PWM_TIPWMSS
+ bool
+ depends on SOC_AM33XX && (PWM_TIEHRPWM || PWM_TIECAP)
+ help
+ PWM Subsystem driver support for AM33xx SOC.
+
+ PWM submodules require PWM config space access from submodule
+ drivers and require common parent driver support.
+
config PWM_TWL6030
tristate "TWL6030 PWM support"
depends on TWL4030_CORE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 3b3f4c9..4fb39f8 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -12,5 +12,6 @@ obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
+obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
new file mode 100644
index 0000000..133635c
--- /dev/null
+++ b/drivers/pwm/pwm-tipwmss.c
@@ -0,0 +1,143 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include "tipwmss.h"
+
+#define PWMSS_CLKCONFIG 0x8 /* Clock gating reg */
+#define PWMSS_CLKSTATUS 0xc /* Clock gating status reg */
+
+struct pwmss_info {
+ void __iomem *mmio_base;
+ struct mutex pwmss_lock;
+ u16 pwmss_clkconfig;
+};
+
+u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+ struct pwmss_info *info = dev_get_drvdata(dev);
+ u16 val;
+
+ mutex_lock(&info->pwmss_lock);
+ val = readw(info->mmio_base + PWMSS_CLKCONFIG);
+ val |= set;
+ writew(val , info->mmio_base + PWMSS_CLKCONFIG);
+ mutex_unlock(&info->pwmss_lock);
+
+ return readw(info->mmio_base + PWMSS_CLKSTATUS);
+}
+EXPORT_SYMBOL(pwmss_submodule_state_change);
+
+static const struct of_device_id pwmss_of_match[] = {
+ {
+ .compatible = "ti,am33xx-pwmss",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pwmss_of_match);
+
+static int pwmss_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *r;
+ struct pwmss_info *info;
+ struct device_node *node = pdev->dev.of_node;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&info->pwmss_lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ return -ENODEV;
+ }
+
+ info->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+ if (!info->mmio_base)
+ return -EADDRNOTAVAIL;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ platform_set_drvdata(pdev, info);
+
+ /* Populate all the child nodes here... */
+ ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ if (ret)
+ dev_err(&pdev->dev, "no child node found\n");
+
+ return ret;
+}
+
+static int pwmss_remove(struct platform_device *pdev)
+{
+ struct pwmss_info *info = platform_get_drvdata(pdev);
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ mutex_destroy(&info->pwmss_lock);
+ return 0;
+}
+
+static int pwmss_suspend(struct device *dev)
+{
+ struct pwmss_info *info = dev_get_drvdata(dev);
+
+ info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG);
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int pwmss_resume(struct device *dev)
+{
+ struct pwmss_info *info = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+ writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG);
+ return 0;
+}
+
+static const struct dev_pm_ops pwmss_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pwmss_suspend, pwmss_resume)
+};
+
+static struct platform_driver pwmss_driver = {
+ .driver = {
+ .name = "pwmss",
+ .owner = THIS_MODULE,
+ .pm = &pwmss_pm_ops,
+ .of_match_table = pwmss_of_match,
+ },
+ .probe = pwmss_probe,
+ .remove = pwmss_remove,
+};
+
+module_platform_driver(pwmss_driver);
+
+MODULE_DESCRIPTION("PWM Subsystem driver");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/tipwmss.h b/drivers/pwm/tipwmss.h
new file mode 100644
index 0000000..11f76a1
--- /dev/null
+++ b/drivers/pwm/tipwmss.h
@@ -0,0 +1,39 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __TIPWMSS_H
+#define __TIPWMSS_H
+
+#ifdef CONFIG_PWM_TIPWMSS
+/* PWM substem clock gating */
+#define PWMSS_ECAPCLK_EN BIT(0)
+#define PWMSS_ECAPCLK_STOP_REQ BIT(1)
+#define PWMSS_EPWMCLK_EN BIT(8)
+#define PWMSS_EPWMCLK_STOP_REQ BIT(9)
+
+#define PWMSS_ECAPCLK_EN_ACK BIT(0)
+#define PWMSS_EPWMCLK_EN_ACK BIT(8)
+
+extern u16 pwmss_submodule_state_change(struct device *dev, int set);
+#else
+static inline u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+ /* return success status value */
+ return 0xFFFF;
+}
+#endif
+#endif /* __TIPWMSS_H */
--
1.7.0.4

2012-11-20 05:12:07

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 04/10] pwm: pwm-tiecap: Add device-tree binding support for APWM driver

This patch
1. Add support for device-tree binding for ECAP APWM driver.
2. Set size of pwm-cells set to 3 to support PWM channel number, PWM
period & polarity configuration from device tree.
3. Add enable/disable clock gating in PWM subsystem common config space.
4. When here set .owner member in platform_driver structure to
THIS_MODULE.

Signed-off-by: Philip, Avinash <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
---
Changes since v2:
- Add of_pwm_xlate_with_flags function support

Changes since v1:
- Add separate patch for pinctrl support
- Add conditional check for PWM subsystem clock enable.
- Combined with HWMOD changes & DT bindings.
- Remove the custom of_xlate support.

:000000 100644 0000000... 131e8c1... A Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
:100644 100644 d6d4cf0... 351199b... M drivers/pwm/pwm-tiecap.c
.../devicetree/bindings/pwm/pwm-tiecap.txt | 23 ++++++++++
drivers/pwm/pwm-tiecap.c | 44 +++++++++++++++++++-
2 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
new file mode 100644
index 0000000..131e8c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
@@ -0,0 +1,23 @@
+TI SOC ECAP based APWM controller
+
+Required properties:
+- compatible: Must be "ti,am33xx-ecap"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+ First cell specifies the per-chip index of the PWM to use, the second
+ cell is the period in nanoseconds and bit 0 in the third cell is used to
+ encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+ to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the ECAP:
+ "ecap<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ecap0: ecap@0 {
+ compatible = "ti,am33xx-ecap";
+ #pwm-cells = <3>;
+ reg = <0x48300100 0x80>;
+ ti,hwmods = "ecap0";
+};
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index d6d4cf0..351199b 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -25,6 +25,9 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
+#include <linux/of_device.h>
+
+#include "tipwmss.h"

/* ECAP registers and bits definitions */
#define CAP1 0x08
@@ -184,12 +187,21 @@ static const struct pwm_ops ecap_pwm_ops = {
.owner = THIS_MODULE,
};

+static const struct of_device_id ecap_of_match[] = {
+ {
+ .compatible = "ti,am33xx-ecap",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ecap_of_match);
+
static int __devinit ecap_pwm_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
struct clk *clk;
struct ecap_pwm_chip *pc;
+ u16 status;

pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc) {
@@ -211,6 +223,8 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)

pc->chip.dev = &pdev->dev;
pc->chip.ops = &ecap_pwm_ops;
+ pc->chip.of_xlate = of_pwm_xlate_with_flags;
+ pc->chip.of_pwm_n_cells = 3;
pc->chip.base = -1;
pc->chip.npwm = 1;

@@ -231,14 +245,40 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)
}

pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ status = pwmss_submodule_state_change(pdev->dev.parent,
+ PWMSS_ECAPCLK_EN);
+ if (!(status & PWMSS_ECAPCLK_EN_ACK)) {
+ dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+ ret = -EINVAL;
+ goto pwmss_clk_failure;
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+
platform_set_drvdata(pdev, pc);
return 0;
+
+pwmss_clk_failure:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pwmchip_remove(&pc->chip);
+ return ret;
}

static int __devexit ecap_pwm_remove(struct platform_device *pdev)
{
struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);

+ pm_runtime_get_sync(&pdev->dev);
+ /*
+ * Due to hardware misbehaviour, acknowledge of the stop_req
+ * is missing. Hence checking of the status bit skipped.
+ */
+ pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
+ pm_runtime_put_sync(&pdev->dev);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return pwmchip_remove(&pc->chip);
@@ -246,7 +286,9 @@ static int __devexit ecap_pwm_remove(struct platform_device *pdev)

static struct platform_driver ecap_pwm_driver = {
.driver = {
- .name = "ecap",
+ .name = "ecap",
+ .owner = THIS_MODULE,
+ .of_match_table = ecap_of_match,
},
.probe = ecap_pwm_probe,
.remove = __devexit_p(ecap_pwm_remove),
--
1.7.0.4

2012-11-20 05:12:34

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 05/10] pwm: pwm-tiecap: pinctrl support

Enable pinctrl for pwm-tiecap

Signed-off-by: Philip, Avinash <[email protected]>
---
:100644 100644 351199b... 3b66e22... M drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiecap.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 351199b..3b66e22 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -26,6 +26,7 @@
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>

#include "tipwmss.h"

@@ -202,6 +203,11 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)
struct clk *clk;
struct ecap_pwm_chip *pc;
u16 status;
+ struct pinctrl *pinctrl;
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev, "failed to configure pins from driver\n");

pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc) {
--
1.7.0.4

2012-11-20 05:14:06

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 06/10] pwm: pwm-tiehrpwm: Add device-tree binding support for EHRPWM driver

This patch
1. Add support for device-tree binding for EHRWPM driver.
2. Set size of pwm-cells set to 3 to support PWM channel number, PWM
period & polarity configuration from device tree.
3. Add enable/disable clock gating in PWM subsystem common config space.
4. When here set .owner member in platform_driver structure to
THIS_MODULE.

Signed-off-by: Philip, Avinash <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
---
Changes since v2:
- Add of_pwm_xlate_with_flags function support

Changes since v1:
- Add separate patch for pinctrl support
- Add conditional check for PWM subsystem clock enable.
- Combined with HWMOD changes & DT bindings.
- Remove the custom of_xlate support.

:000000 100644 0000000... 4fc7079... A Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
:100644 100644 d3c1dff... b7e63fb... M drivers/pwm/pwm-tiehrpwm.c
.../devicetree/bindings/pwm/pwm-tiehrpwm.txt | 23 ++++++++++
drivers/pwm/pwm-tiehrpwm.c | 45 +++++++++++++++++++-
2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
new file mode 100644
index 0000000..4fc7079
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
@@ -0,0 +1,23 @@
+TI SOC EHRPWM based PWM controller
+
+Required properties:
+- compatible : Must be "ti,am33xx-ehrpwm"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+ First cell specifies the per-chip index of the PWM to use, the second
+ cell is the period in nanoseconds and bit 0 in the third cell is used to
+ encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+ to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the EHRPWM:
+ "ehrpwm<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ehrpwm0: ehrpwm@0 {
+ compatible = "ti,am33xx-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x48300200 0x100>;
+ ti,hwmods = "ehrpwm0";
+};
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index d3c1dff..b7e63fb 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -25,6 +25,9 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include "tipwmss.h"

/* EHRPWM registers and bits definitions */

@@ -392,12 +395,21 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
.owner = THIS_MODULE,
};

+static const struct of_device_id ehrpwm_of_match[] = {
+ {
+ .compatible = "ti,am33xx-ehrpwm",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
+
static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
struct clk *clk;
struct ehrpwm_pwm_chip *pc;
+ u16 status;

pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc) {
@@ -419,6 +431,8 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)

pc->chip.dev = &pdev->dev;
pc->chip.ops = &ehrpwm_pwm_ops;
+ pc->chip.of_xlate = of_pwm_xlate_with_flags;
+ pc->chip.of_pwm_n_cells = 3;
pc->chip.base = -1;
pc->chip.npwm = NUM_PWM_CHANNEL;

@@ -437,16 +451,41 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
return ret;
}
-
pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ status = pwmss_submodule_state_change(pdev->dev.parent,
+ PWMSS_EPWMCLK_EN);
+ if (!(status & PWMSS_EPWMCLK_EN_ACK)) {
+ dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+ ret = -EINVAL;
+ goto pwmss_clk_failure;
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+
platform_set_drvdata(pdev, pc);
return 0;
+
+pwmss_clk_failure:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pwmchip_remove(&pc->chip);
+ return ret;
}

static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev)
{
struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);

+ pm_runtime_get_sync(&pdev->dev);
+ /*
+ * Due to hardware misbehaviour, acknowledge of the stop_req
+ * is missing. Hence checking of the status bit skipped.
+ */
+ pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ);
+ pm_runtime_put_sync(&pdev->dev);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return pwmchip_remove(&pc->chip);
@@ -454,7 +493,9 @@ static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev)

static struct platform_driver ehrpwm_pwm_driver = {
.driver = {
- .name = "ehrpwm",
+ .name = "ehrpwm",
+ .owner = THIS_MODULE,
+ .of_match_table = ehrpwm_of_match,
},
.probe = ehrpwm_pwm_probe,
.remove = __devexit_p(ehrpwm_pwm_remove),
--
1.7.0.4

2012-11-20 05:14:30

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 07/10] pwm: pwm-tiehrpwm: pinctrl support

Enable pinctrl for pwm-tiehrpwm

Signed-off-by: Philip, Avinash <[email protected]>
---
:100644 100644 b7e63fb... 1cb54aa... M drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tiehrpwm.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index b7e63fb..1cb54aa 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>

#include "tipwmss.h"

@@ -410,6 +411,11 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
struct clk *clk;
struct ehrpwm_pwm_chip *pc;
u16 status;
+ struct pinctrl *pinctrl;
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev, "failed to configure pins from driver\n");

pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc) {
--
1.7.0.4

2012-11-20 05:14:57

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 08/10] pwm: pwm-tiehrpwm: Adding TBCLK gating support.

Some platforms (like AM33XX) requires clock gating from control module
explicitly for TBCLK. Enabling of this clock required for the
functioning of the time base sub module in EHRPWM module. So adding
optional TBCLK handling.

Signed-off-by: Philip, Avinash <[email protected]>
---
Changes since v2:
- Remove DT property for tbclkgating
- Use devm_clk_get instead of clk_get

Changes since v1:
- Moved TBCLK enable from probe to .pwm_enable & disable from
remove to .pwm_disable

:100644 100644 1cb54aa... 1298f19... M drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tiehrpwm.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 1cb54aa..1298f19 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -119,6 +119,7 @@ struct ehrpwm_pwm_chip {
void __iomem *mmio_base;
unsigned long period_cycles[NUM_PWM_CHANNEL];
enum pwm_polarity polarity[NUM_PWM_CHANNEL];
+ struct clk *tbclk;
};

static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -339,6 +340,13 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
/* Channels polarity can be configured from action qualifier module */
configure_polarity(pc, pwm->hwpwm);

+ /*
+ * Platforms require explicit clock enabling of TBCLK has
+ * to enable TBCLK explicitly before enabling PWM device
+ */
+ if (pc->tbclk)
+ clk_enable(pc->tbclk);
+
/* Enable time counter for free_run */
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
return 0;
@@ -367,6 +375,10 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)

ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);

+ /* Disabling TBCLK on PWM disable */
+ if (pc->tbclk)
+ clk_disable(pc->tbclk);
+
/* Stop Time base counter */
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);

@@ -457,6 +469,10 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
return ret;
}
+
+ /* Populate tbclk entry for platforms require explicit tbclk gating */
+ pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
+
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);

--
1.7.0.4

2012-11-20 05:15:07

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 09/10] ARM: dts: AM33XX: Add PWMSS device tree nodes

Add PWMSS device tree nodes in relation with ECAP & EHRPWM DT nodes to
AM33XX SoC family. Also populates device tree nodes for ECAP & EHRPWM by
adding necessary properties like pwm-cells, base reg & set disabled as
status.

Signed-off-by: Philip, Avinash <[email protected]>
---
Changes since v2:
- ranges property populated to handle child devices address range

:100644 100644 bb31bff... 75daf1d... M arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am33xx.dtsi | 84 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index bb31bff..75daf1d 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -210,5 +210,89 @@
interrupt-parent = <&intc>;
interrupts = <91>;
};
+
+ epwmss0: epwmss@48300000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48300000 0x10>;
+ ti,hwmods = "epwmss0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges = <0x48300100 0x48300100 0x80 /* ECAP */
+ 0x48300180 0x48300180 0x80 /* EQEP */
+ 0x48300200 0x48300200 0x80>; /* EHRPWM */
+
+ ecap0: ecap@48300100 {
+ compatible = "ti,am33xx-ecap";
+ #pwm-cells = <3>;
+ reg = <0x48300100 0x80>;
+ ti,hwmods = "ecap0";
+ status = "disabled";
+ };
+
+ ehrpwm0: ehrpwm@48300200 {
+ compatible = "ti,am33xx-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x48300200 0x80>;
+ ti,hwmods = "ehrpwm0";
+ status = "disabled";
+ };
+ };
+
+ epwmss1: epwmss@48302000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48302000 0x10>;
+ ti,hwmods = "epwmss1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges = <0x48302100 0x48302100 0x80 /* ECAP */
+ 0x48302180 0x48302180 0x80 /* EQEP */
+ 0x48302200 0x48302200 0x80>; /* EHRPWM */
+
+ ecap1: ecap@48302100 {
+ compatible = "ti,am33xx-ecap";
+ #pwm-cells = <3>;
+ reg = <0x48302100 0x80>;
+ ti,hwmods = "ecap1";
+ status = "disabled";
+ };
+
+ ehrpwm1: ehrpwm@48302200 {
+ compatible = "ti,am33xx-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x48302200 0x80>;
+ ti,hwmods = "ehrpwm1";
+ status = "disabled";
+ };
+ };
+
+ epwmss2: epwmss@48304000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48304000 0x10>;
+ ti,hwmods = "epwmss2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges = <0x48304100 0x48304100 0x80 /* ECAP */
+ 0x48304180 0x48304180 0x80 /* EQEP */
+ 0x48304200 0x48304200 0x80>; /* EHRPWM */
+
+ ecap2: ecap@48304100 {
+ compatible = "ti,am33xx-ecap";
+ #pwm-cells = <3>;
+ reg = <0x48304100 0x80>;
+ ti,hwmods = "ecap2";
+ status = "disabled";
+ };
+
+ ehrpwm2: ehrpwm@48304200 {
+ compatible = "ti,am33xx-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x48304200 0x80>;
+ ti,hwmods = "ehrpwm2";
+ status = "disabled";
+ };
+ };
};
};
--
1.7.0.4

2012-11-20 05:15:13

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH v3 10/10] ARM: dts: AM33XX: Add PWM backlight DT data to am335x-evm

PWM output from ecap0 uses as backlight source. Also adds low threshold
value to have a uniform divisions in brightness-levels scales.

Signed-off-by: Philip, Avinash <[email protected]>
---
:100644 100644 185d632... 9857050... M arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am335x-evm.dts | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 185d632..9857050 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -18,6 +18,14 @@
reg = <0x80000000 0x10000000>; /* 256 MB */
};

+ am33xx_pinmux: pinmux@44e10800 {
+ ecap0_pins: backlight_pins {
+ pinctrl-single,pins = <
+ 0x164 0x0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+ >;
+ };
+ };
+
ocp {
uart1: serial@44e09000 {
status = "okay";
@@ -31,6 +39,12 @@
reg = <0x2d>;
};
};
+
+ ecap0: ecap@48300100 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&ecap0_pins>;
+ };
};

vbat: fixedregulator@0 {
@@ -40,6 +54,13 @@
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&ecap0 0 50000 0>;
+ brightness-levels = <0 51 53 56 62 75 101 152 255>;
+ default-brightness-level = <8>;
+ };
};

/include/ "tps65910.dtsi"
--
1.7.0.4

2012-11-23 11:05:16

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH v3 02/10] ARM: am33xx: clk: Add optional clock for EHRPWM

On Tue, Nov 20, 2012 at 10:33:43, Philip, Avinash wrote:
> EHRPWM module requires explicit clock gating from control module.
> Hence add clock node in clock tree for EHRPWM modules.
>

Is there any review on this patch?
This patch depends on EHRPWM to work in am335x.

Thanks
Avinash
> Signed-off-by: Philip, Avinash <[email protected]>
> ---
> :100644 100644 17e3de5... 833260f... M arch/arm/mach-omap2/clock33xx_data.c
> :100644 100644 a89e825... c0e34e6... M arch/arm/mach-omap2/control.h
> arch/arm/mach-omap2/clock33xx_data.c | 37 ++++++++++++++++++++++++++++++++++
> arch/arm/mach-omap2/control.h | 8 +++++++
> 2 files changed, 45 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
> index 17e3de5..833260f 100644
> --- a/arch/arm/mach-omap2/clock33xx_data.c
> +++ b/arch/arm/mach-omap2/clock33xx_data.c
> @@ -995,6 +995,40 @@ static struct clk wdt1_fck = {
> };
>
> /*
> + * PWMSS Time based module clock node. This node is
> + * requred to enable clock gating for EHRPWM TBCLK.
> + */
> +static struct clk ehrpwm0_tbclk = {
> + .name = "ehrpwm0_tbclk",
> + .clkdm_name = "l4ls_clkdm",
> + .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
> + .enable_bit = AM33XX_PWMSS0_TBCLKEN_SHIFT,
> + .ops = &clkops_omap2_dflt,
> + .parent = &l4ls_gclk,
> + .recalc = &followparent_recalc,
> +};
> +
> +static struct clk ehrpwm1_tbclk = {
> + .name = "ehrpwm1_tbclk",
> + .clkdm_name = "l4ls_clkdm",
> + .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
> + .enable_bit = AM33XX_PWMSS1_TBCLKEN_SHIFT,
> + .ops = &clkops_omap2_dflt,
> + .parent = &l4ls_gclk,
> + .recalc = &followparent_recalc,
> +};
> +
> +static struct clk ehrpwm2_tbclk = {
> + .name = "ehrpwm2_tbclk",
> + .clkdm_name = "l4ls_clkdm",
> + .enable_reg = AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
> + .enable_bit = AM33XX_PWMSS2_TBCLKEN_SHIFT,
> + .ops = &clkops_omap2_dflt,
> + .parent = &l4ls_gclk,
> + .recalc = &followparent_recalc,
> +};
> +
> +/*
> * clkdev
> */
> static struct omap_clk am33xx_clks[] = {
> @@ -1074,6 +1108,9 @@ static struct omap_clk am33xx_clks[] = {
> CLK(NULL, "clkout2_ck", &clkout2_ck, CK_AM33XX),
> CLK(NULL, "timer_32k_ck", &clkdiv32k_ick, CK_AM33XX),
> CLK(NULL, "timer_sys_ck", &sys_clkin_ck, CK_AM33XX),
> + CLK(NULL, "ehrpwm0_tbclk", &ehrpwm0_tbclk, CK_AM33XX),
> + CLK(NULL, "ehrpwm1_tbclk", &ehrpwm1_tbclk, CK_AM33XX),
> + CLK(NULL, "ehrpwm2_tbclk", &ehrpwm2_tbclk, CK_AM33XX),
> };
>
> int __init am33xx_clk_init(void)
> diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
> index a89e825..c0e34e6 100644
> --- a/arch/arm/mach-omap2/control.h
> +++ b/arch/arm/mach-omap2/control.h
> @@ -357,6 +357,14 @@
> #define AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH 0x2
> #define AM33XX_CONTROL_STATUS_SYSBOOT1_MASK (0x3 << 22)
>
> +/* AM33XX PWMSS Control register */
> +#define AM33XX_PWMSS_TBCLK_CLKCTRL 0x664
> +
> +/* AM33XX PWMSS Control bitfields */
> +#define AM33XX_PWMSS0_TBCLKEN_SHIFT 0
> +#define AM33XX_PWMSS1_TBCLKEN_SHIFT 1
> +#define AM33XX_PWMSS2_TBCLKEN_SHIFT 2
> +
> /* CONTROL OMAP STATUS register to identify OMAP3 features */
> #define OMAP3_CONTROL_OMAP_STATUS 0x044c
>
> --
> 1.7.0.4
>
>

2012-11-23 11:07:27

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

On Tue, Nov 20, 2012 at 10:33:44, Philip, Avinash wrote:
> As part of PWM subsystem integration, PWM subsystem are sharing
> resources like clock across submodules (ECAP, EQEP & EHRPWM).
> To handle resource sharing & IP integration
> 1. Rework on parent child relation between PWMSS and
> ECAP, EQEP & EHRPWM child devices to support runtime PM.
> 2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
> clock gating from control module.
> 3. Add HWMOD entries for EQEP PWM submodule.
>

Is there any review on this patch?
This patch depends on ECAP & EHRPWM to work in am335x.

Thanks
Avinash

> Signed-off-by: Philip, Avinash <[email protected]>
> ---
> Changes since v1:
> - Remove ADDR_TYPE_RT for PWM sub module register entries.
>
> :100644 100644 ad8d43b... de2301c... M arch/arm/mach-omap2/omap_hwmod_33xx_data.c
> arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 419 ++++++++++++++++++----------
> 1 files changed, 276 insertions(+), 143 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
> index ad8d43b..de2301c 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
> @@ -768,9 +768,7 @@ static struct omap_hwmod am33xx_elm_hwmod = {
> },
> };
>
> -/*
> - * 'epwmss' class: ecap0,1,2, ehrpwm0,1,2
> - */
> +/* pwmss */
> static struct omap_hwmod_class_sysconfig am33xx_epwmss_sysc = {
> .rev_offs = 0x0,
> .sysc_offs = 0x4,
> @@ -786,18 +784,23 @@ static struct omap_hwmod_class am33xx_epwmss_hwmod_class = {
> .sysc = &am33xx_epwmss_sysc,
> };
>
> -/* ehrpwm0 */
> -static struct omap_hwmod_irq_info am33xx_ehrpwm0_irqs[] = {
> - { .name = "int", .irq = 86 + OMAP_INTC_START, },
> - { .name = "tzint", .irq = 58 + OMAP_INTC_START, },
> - { .irq = -1 },
> +
> +static struct omap_hwmod_class am33xx_ecap_hwmod_class = {
> + .name = "ecap",
> };
>
> -static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
> - .name = "ehrpwm0",
> +static struct omap_hwmod_class am33xx_eqep_hwmod_class = {
> + .name = "eqep",
> +};
> +
> +static struct omap_hwmod_class am33xx_ehrpwm_hwmod_class = {
> + .name = "ehrpwm",
> +};
> +/* epwmss0 */
> +static struct omap_hwmod am33xx_epwmss0_hwmod = {
> + .name = "epwmss0",
> .class = &am33xx_epwmss_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> - .mpu_irqs = am33xx_ehrpwm0_irqs,
> .main_clk = "l4ls_gclk",
> .prcm = {
> .omap4 = {
> @@ -807,63 +810,68 @@ static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
> },
> };
>
> -/* ehrpwm1 */
> -static struct omap_hwmod_irq_info am33xx_ehrpwm1_irqs[] = {
> - { .name = "int", .irq = 87 + OMAP_INTC_START, },
> - { .name = "tzint", .irq = 59 + OMAP_INTC_START, },
> +/* ecap0 */
> +static struct omap_hwmod_irq_info am33xx_ecap0_irqs[] = {
> + { .irq = 31 + OMAP_INTC_START, },
> { .irq = -1 },
> };
>
> -static struct omap_hwmod am33xx_ehrpwm1_hwmod = {
> - .name = "ehrpwm1",
> - .class = &am33xx_epwmss_hwmod_class,
> +static struct omap_hwmod am33xx_ecap0_hwmod = {
> + .name = "ecap0",
> + .class = &am33xx_ecap_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> - .mpu_irqs = am33xx_ehrpwm1_irqs,
> + .mpu_irqs = am33xx_ecap0_irqs,
> .main_clk = "l4ls_gclk",
> - .prcm = {
> - .omap4 = {
> - .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
> - .modulemode = MODULEMODE_SWCTRL,
> - },
> - },
> };
>
> -/* ehrpwm2 */
> -static struct omap_hwmod_irq_info am33xx_ehrpwm2_irqs[] = {
> - { .name = "int", .irq = 39 + OMAP_INTC_START, },
> - { .name = "tzint", .irq = 60 + OMAP_INTC_START, },
> +/* eqep0 */
> +static struct omap_hwmod_irq_info am33xx_eqep0_irqs[] = {
> + { .irq = 79 + OMAP_INTC_START, },
> { .irq = -1 },
> };
>
> -static struct omap_hwmod am33xx_ehrpwm2_hwmod = {
> - .name = "ehrpwm2",
> - .class = &am33xx_epwmss_hwmod_class,
> +static struct omap_hwmod am33xx_eqep0_hwmod = {
> + .name = "eqep0",
> + .class = &am33xx_eqep_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> - .mpu_irqs = am33xx_ehrpwm2_irqs,
> + .mpu_irqs = am33xx_eqep0_irqs,
> .main_clk = "l4ls_gclk",
> - .prcm = {
> - .omap4 = {
> - .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
> - .modulemode = MODULEMODE_SWCTRL,
> - },
> - },
> };
>
> -/* ecap0 */
> -static struct omap_hwmod_irq_info am33xx_ecap0_irqs[] = {
> - { .irq = 31 + OMAP_INTC_START, },
> +/* ehrpwm0 */
> +static struct omap_hwmod_irq_info am33xx_ehrpwm0_irqs[] = {
> + { .name = "int", .irq = 86 + OMAP_INTC_START, },
> + { .name = "tzint", .irq = 58 + OMAP_INTC_START, },
> { .irq = -1 },
> };
>
> -static struct omap_hwmod am33xx_ecap0_hwmod = {
> - .name = "ecap0",
> +/*
> + * Optional clock entry is provided to support additional clock
> + * gating for EHRPWM module functional from control module.
> + */
> +static struct omap_hwmod_opt_clk ehrpwm0_opt_clks[] = {
> + { .role = "tbclk", .clk = "ehrpwm0_tbclk" },
> +};
> +
> +static struct omap_hwmod am33xx_ehrpwm0_hwmod = {
> + .name = "ehrpwm0",
> + .class = &am33xx_ehrpwm_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> + .mpu_irqs = am33xx_ehrpwm0_irqs,
> + .main_clk = "l4ls_gclk",
> + .opt_clks = ehrpwm0_opt_clks,
> + .opt_clks_cnt = ARRAY_SIZE(ehrpwm0_opt_clks),
> +};
> +
> +/* epwmss1 */
> +static struct omap_hwmod am33xx_epwmss1_hwmod = {
> + .name = "epwmss1",
> .class = &am33xx_epwmss_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> - .mpu_irqs = am33xx_ecap0_irqs,
> .main_clk = "l4ls_gclk",
> .prcm = {
> .omap4 = {
> - .clkctrl_offs = AM33XX_CM_PER_EPWMSS0_CLKCTRL_OFFSET,
> + .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
> .modulemode = MODULEMODE_SWCTRL,
> },
> },
> @@ -877,13 +885,60 @@ static struct omap_hwmod_irq_info am33xx_ecap1_irqs[] = {
>
> static struct omap_hwmod am33xx_ecap1_hwmod = {
> .name = "ecap1",
> - .class = &am33xx_epwmss_hwmod_class,
> + .class = &am33xx_ecap_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> .mpu_irqs = am33xx_ecap1_irqs,
> .main_clk = "l4ls_gclk",
> +};
> +
> +/* eqep1 */
> +static struct omap_hwmod_irq_info am33xx_eqep1_irqs[] = {
> + { .irq = 88 + OMAP_INTC_START, },
> + { .irq = -1 },
> +};
> +
> +static struct omap_hwmod am33xx_eqep1_hwmod = {
> + .name = "eqep1",
> + .class = &am33xx_eqep_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> + .mpu_irqs = am33xx_eqep1_irqs,
> + .main_clk = "l4ls_gclk",
> +};
> +
> +/* ehrpwm1 */
> +static struct omap_hwmod_irq_info am33xx_ehrpwm1_irqs[] = {
> + { .name = "int", .irq = 87 + OMAP_INTC_START, },
> + { .name = "tzint", .irq = 59 + OMAP_INTC_START, },
> + { .irq = -1 },
> +};
> +
> +/*
> + * Optional clock entry is provided to support additional clock
> + * gating for EHRPWM module functional from control module.
> + */
> +static struct omap_hwmod_opt_clk ehrpwm1_opt_clks[] = {
> + { .role = "tbclk", .clk = "ehrpwm1_tbclk" },
> +};
> +
> +static struct omap_hwmod am33xx_ehrpwm1_hwmod = {
> + .name = "ehrpwm1",
> + .class = &am33xx_ehrpwm_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> + .mpu_irqs = am33xx_ehrpwm1_irqs,
> + .main_clk = "l4ls_gclk",
> + .opt_clks = ehrpwm1_opt_clks,
> + .opt_clks_cnt = ARRAY_SIZE(ehrpwm1_opt_clks),
> +};
> +
> +/* epwmss2 */
> +static struct omap_hwmod am33xx_epwmss2_hwmod = {
> + .name = "epwmss2",
> + .class = &am33xx_epwmss_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> + .main_clk = "l4ls_gclk",
> .prcm = {
> .omap4 = {
> - .clkctrl_offs = AM33XX_CM_PER_EPWMSS1_CLKCTRL_OFFSET,
> + .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
> .modulemode = MODULEMODE_SWCTRL,
> },
> },
> @@ -897,16 +952,49 @@ static struct omap_hwmod_irq_info am33xx_ecap2_irqs[] = {
>
> static struct omap_hwmod am33xx_ecap2_hwmod = {
> .name = "ecap2",
> + .class = &am33xx_ecap_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> .mpu_irqs = am33xx_ecap2_irqs,
> - .class = &am33xx_epwmss_hwmod_class,
> + .main_clk = "l4ls_gclk",
> +};
> +
> +/* eqep2 */
> +static struct omap_hwmod_irq_info am33xx_eqep2_irqs[] = {
> + { .irq = 89 + OMAP_INTC_START, },
> + { .irq = -1 },
> +};
> +
> +static struct omap_hwmod am33xx_eqep2_hwmod = {
> + .name = "eqep2",
> + .class = &am33xx_eqep_hwmod_class,
> .clkdm_name = "l4ls_clkdm",
> + .mpu_irqs = am33xx_eqep2_irqs,
> .main_clk = "l4ls_gclk",
> - .prcm = {
> - .omap4 = {
> - .clkctrl_offs = AM33XX_CM_PER_EPWMSS2_CLKCTRL_OFFSET,
> - .modulemode = MODULEMODE_SWCTRL,
> - },
> - },
> +};
> +
> +/* ehrpwm2 */
> +static struct omap_hwmod_irq_info am33xx_ehrpwm2_irqs[] = {
> + { .name = "int", .irq = 39 + OMAP_INTC_START, },
> + { .name = "tzint", .irq = 60 + OMAP_INTC_START, },
> + { .irq = -1 },
> +};
> +
> +/*
> + * Optional clock entry is provided to support additional clock
> + * gating for EHRPWM module functional from control module.
> + */
> +static struct omap_hwmod_opt_clk ehrpwm2_opt_clks[] = {
> + { .role = "tbclk", .clk = "ehrpwm2_tbclk" },
> +};
> +
> +static struct omap_hwmod am33xx_ehrpwm2_hwmod = {
> + .name = "ehrpwm2",
> + .class = &am33xx_ehrpwm_hwmod_class,
> + .clkdm_name = "l4ls_clkdm",
> + .mpu_irqs = am33xx_ehrpwm2_irqs,
> + .main_clk = "l4ls_gclk",
> + .opt_clks = ehrpwm2_opt_clks,
> + .opt_clks_cnt = ARRAY_SIZE(ehrpwm2_opt_clks),
> };
>
> /*
> @@ -2518,162 +2606,201 @@ static struct omap_hwmod_ocp_if am33xx_l4_ls__elm = {
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
> +static struct omap_hwmod_addr_space am33xx_epwmss0_addr_space[] = {
> {
> .pa_start = 0x48300000,
> .pa_end = 0x48300000 + SZ_16 - 1,
> .flags = ADDR_TYPE_RT
> },
> - {
> - .pa_start = 0x48300200,
> - .pa_end = 0x48300200 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> - },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm0 = {
> +static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss0 = {
> .master = &am33xx_l4_ls_hwmod,
> - .slave = &am33xx_ehrpwm0_hwmod,
> + .slave = &am33xx_epwmss0_hwmod,
> .clk = "l4ls_gclk",
> - .addr = am33xx_ehrpwm0_addr_space,
> + .addr = am33xx_epwmss0_addr_space,
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = {
> - {
> - .pa_start = 0x48302000,
> - .pa_end = 0x48302000 + SZ_16 - 1,
> - .flags = ADDR_TYPE_RT
> - },
> +static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
> {
> - .pa_start = 0x48302200,
> - .pa_end = 0x48302200 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> + .pa_start = 0x48300100,
> + .pa_end = 0x48300100 + SZ_128 - 1,
> },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm1 = {
> - .master = &am33xx_l4_ls_hwmod,
> - .slave = &am33xx_ehrpwm1_hwmod,
> +static struct omap_hwmod_ocp_if am33xx_epwmss0__ecap0 = {
> + .master = &am33xx_epwmss0_hwmod,
> + .slave = &am33xx_ecap0_hwmod,
> .clk = "l4ls_gclk",
> - .addr = am33xx_ehrpwm1_addr_space,
> + .addr = am33xx_ecap0_addr_space,
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = {
> +static struct omap_hwmod_addr_space am33xx_eqep0_addr_space[] = {
> {
> - .pa_start = 0x48304000,
> - .pa_end = 0x48304000 + SZ_16 - 1,
> - .flags = ADDR_TYPE_RT
> - },
> - {
> - .pa_start = 0x48304200,
> - .pa_end = 0x48304200 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> + .pa_start = 0x48300180,
> + .pa_end = 0x48300180 + SZ_128 - 1,
> },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm2 = {
> - .master = &am33xx_l4_ls_hwmod,
> - .slave = &am33xx_ehrpwm2_hwmod,
> +static struct omap_hwmod_ocp_if am33xx_epwmss0__eqep0 = {
> + .master = &am33xx_epwmss0_hwmod,
> + .slave = &am33xx_eqep0_hwmod,
> .clk = "l4ls_gclk",
> - .addr = am33xx_ehrpwm2_addr_space,
> + .addr = am33xx_eqep0_addr_space,
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
> - {
> - .pa_start = 0x48300000,
> - .pa_end = 0x48300000 + SZ_16 - 1,
> - .flags = ADDR_TYPE_RT
> - },
> +static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
> {
> - .pa_start = 0x48300100,
> - .pa_end = 0x48300100 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> + .pa_start = 0x48300200,
> + .pa_end = 0x48300200 + SZ_128 - 1,
> },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap0 = {
> - .master = &am33xx_l4_ls_hwmod,
> - .slave = &am33xx_ecap0_hwmod,
> +static struct omap_hwmod_ocp_if am33xx_epwmss0__ehrpwm0 = {
> + .master = &am33xx_epwmss0_hwmod,
> + .slave = &am33xx_ehrpwm0_hwmod,
> .clk = "l4ls_gclk",
> - .addr = am33xx_ecap0_addr_space,
> + .addr = am33xx_ehrpwm0_addr_space,
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = {
> +static struct omap_hwmod_addr_space am33xx_epwmss1_addr_space[] = {
> {
> .pa_start = 0x48302000,
> .pa_end = 0x48302000 + SZ_16 - 1,
> .flags = ADDR_TYPE_RT
> },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss1 = {
> + .master = &am33xx_l4_ls_hwmod,
> + .slave = &am33xx_epwmss1_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_epwmss1_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> +static struct omap_hwmod_addr_space am33xx_ecap1_addr_space[] = {
> {
> .pa_start = 0x48302100,
> - .pa_end = 0x48302100 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> + .pa_end = 0x48302100 + SZ_128 - 1,
> },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap1 = {
> - .master = &am33xx_l4_ls_hwmod,
> +static struct omap_hwmod_ocp_if am33xx_epwmss1__ecap1 = {
> + .master = &am33xx_epwmss1_hwmod,
> .slave = &am33xx_ecap1_hwmod,
> .clk = "l4ls_gclk",
> .addr = am33xx_ecap1_addr_space,
> .user = OCP_USER_MPU,
> };
>
> -/*
> - * Splitting the resources to handle access of PWMSS config space
> - * and module specific part independently
> - */
> -static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = {
> +static struct omap_hwmod_addr_space am33xx_eqep1_addr_space[] = {
> + {
> + .pa_start = 0x48302180,
> + .pa_end = 0x48302180 + SZ_128 - 1,
> + },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_epwmss1__eqep1 = {
> + .master = &am33xx_epwmss1_hwmod,
> + .slave = &am33xx_eqep1_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_eqep1_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> +static struct omap_hwmod_addr_space am33xx_ehrpwm1_addr_space[] = {
> + {
> + .pa_start = 0x48302200,
> + .pa_end = 0x48302200 + SZ_128 - 1,
> + },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_epwmss1__ehrpwm1 = {
> + .master = &am33xx_epwmss1_hwmod,
> + .slave = &am33xx_ehrpwm1_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_ehrpwm1_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> +static struct omap_hwmod_addr_space am33xx_epwmss2_addr_space[] = {
> {
> .pa_start = 0x48304000,
> .pa_end = 0x48304000 + SZ_16 - 1,
> .flags = ADDR_TYPE_RT
> },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss2 = {
> + .master = &am33xx_l4_ls_hwmod,
> + .slave = &am33xx_epwmss2_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_epwmss2_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> +static struct omap_hwmod_addr_space am33xx_ecap2_addr_space[] = {
> {
> .pa_start = 0x48304100,
> - .pa_end = 0x48304100 + SZ_256 - 1,
> - .flags = ADDR_TYPE_RT
> + .pa_end = 0x48304100 + SZ_128 - 1,
> },
> { }
> };
>
> -static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap2 = {
> - .master = &am33xx_l4_ls_hwmod,
> +static struct omap_hwmod_ocp_if am33xx_epwmss2__ecap2 = {
> + .master = &am33xx_epwmss2_hwmod,
> .slave = &am33xx_ecap2_hwmod,
> .clk = "l4ls_gclk",
> .addr = am33xx_ecap2_addr_space,
> .user = OCP_USER_MPU,
> };
>
> +static struct omap_hwmod_addr_space am33xx_eqep2_addr_space[] = {
> + {
> + .pa_start = 0x48304180,
> + .pa_end = 0x48304180 + SZ_128 - 1,
> + },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_epwmss2__eqep2 = {
> + .master = &am33xx_epwmss2_hwmod,
> + .slave = &am33xx_eqep2_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_eqep2_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> +static struct omap_hwmod_addr_space am33xx_ehrpwm2_addr_space[] = {
> + {
> + .pa_start = 0x48304200,
> + .pa_end = 0x48304200 + SZ_128 - 1,
> + },
> + { }
> +};
> +
> +static struct omap_hwmod_ocp_if am33xx_epwmss2__ehrpwm2 = {
> + .master = &am33xx_epwmss2_hwmod,
> + .slave = &am33xx_ehrpwm2_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_ehrpwm2_addr_space,
> + .user = OCP_USER_MPU,
> +};
> +
> /* l3s cfg -> gpmc */
> static struct omap_hwmod_addr_space am33xx_gpmc_addr_space[] = {
> {
> @@ -3356,12 +3483,18 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
> &am33xx_l4_ls__uart6,
> &am33xx_l4_ls__spinlock,
> &am33xx_l4_ls__elm,
> - &am33xx_l4_ls__ehrpwm0,
> - &am33xx_l4_ls__ehrpwm1,
> - &am33xx_l4_ls__ehrpwm2,
> - &am33xx_l4_ls__ecap0,
> - &am33xx_l4_ls__ecap1,
> - &am33xx_l4_ls__ecap2,
> + &am33xx_l4_ls__epwmss0,
> + &am33xx_epwmss0__ecap0,
> + &am33xx_epwmss0__eqep0,
> + &am33xx_epwmss0__ehrpwm0,
> + &am33xx_l4_ls__epwmss1,
> + &am33xx_epwmss1__ecap1,
> + &am33xx_epwmss1__eqep1,
> + &am33xx_epwmss1__ehrpwm1,
> + &am33xx_l4_ls__epwmss2,
> + &am33xx_epwmss2__ecap2,
> + &am33xx_epwmss2__eqep2,
> + &am33xx_epwmss2__ehrpwm2,
> &am33xx_l3_s__gpmc,
> &am33xx_l3_main__lcdc,
> &am33xx_l4_ls__mcspi0,
> --
> 1.7.0.4
>
>

2012-11-26 05:19:52

by Vaibhav Bedia

[permalink] [raw]
Subject: RE: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

On Fri, Nov 23, 2012 at 16:36:06, Philip, Avinash wrote:
> On Tue, Nov 20, 2012 at 10:33:44, Philip, Avinash wrote:
> > As part of PWM subsystem integration, PWM subsystem are sharing
> > resources like clock across submodules (ECAP, EQEP & EHRPWM).
> > To handle resource sharing & IP integration
> > 1. Rework on parent child relation between PWMSS and
> > ECAP, EQEP & EHRPWM child devices to support runtime PM.
> > 2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
> > clock gating from control module.
> > 3. Add HWMOD entries for EQEP PWM submodule.
> >
>
> Is there any review on this patch?
> This patch depends on ECAP & EHRPWM to work in am335x.

First of all, I think you should break up this patch as per the 3 points
that you mentioned above.

The usage of opt_clks for this does not look right to me. Based on your
description this clock is necessary and not optional on AM335x and on
Davinci platforms this clock does not exist.

I think the custom activate/deactivate functions in the OMAP runtime PM
implementation was a good fit for keeping this SoC integration detail out
of the driver code. However, the current DT flow in omap_device.c seems to
assign the default activate/deactivate ops. Is that approach deprecated?

Regards,
Vaibhav

2012-11-26 09:03:37

by Benoit Cousson

[permalink] [raw]
Subject: Re: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

Hi Vaibhav,

On 11/26/2012 06:19 AM, Bedia, Vaibhav wrote:
> On Fri, Nov 23, 2012 at 16:36:06, Philip, Avinash wrote:
>> On Tue, Nov 20, 2012 at 10:33:44, Philip, Avinash wrote:
>>> As part of PWM subsystem integration, PWM subsystem are sharing
>>> resources like clock across submodules (ECAP, EQEP & EHRPWM).
>>> To handle resource sharing & IP integration
>>> 1. Rework on parent child relation between PWMSS and
>>> ECAP, EQEP & EHRPWM child devices to support runtime PM.
>>> 2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
>>> clock gating from control module.
>>> 3. Add HWMOD entries for EQEP PWM submodule.
>>>
>>
>> Is there any review on this patch?
>> This patch depends on ECAP & EHRPWM to work in am335x.
>
> First of all, I think you should break up this patch as per the 3 points
> that you mentioned above.
>
> The usage of opt_clks for this does not look right to me. Based on your
> description this clock is necessary and not optional on AM335x and on
> Davinci platforms this clock does not exist.
>
> I think the custom activate/deactivate functions in the OMAP runtime PM
> implementation was a good fit for keeping this SoC integration detail out
> of the driver code. However, the current DT flow in omap_device.c seems to
> assign the default activate/deactivate ops. Is that approach deprecated?

The issue is that this approach is not doable anymore with DT, that's
why I had to provide a default set of functions.

Regards,
Benoit

2012-11-26 11:08:02

by Vaibhav Bedia

[permalink] [raw]
Subject: RE: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

Hi Benoit,

On Mon, Nov 26, 2012 at 14:32:59, Cousson, Benoit wrote:
> Hi Vaibhav,
>
> On 11/26/2012 06:19 AM, Bedia, Vaibhav wrote:
> > On Fri, Nov 23, 2012 at 16:36:06, Philip, Avinash wrote:
> >> On Tue, Nov 20, 2012 at 10:33:44, Philip, Avinash wrote:
> >>> As part of PWM subsystem integration, PWM subsystem are sharing
> >>> resources like clock across submodules (ECAP, EQEP & EHRPWM).
> >>> To handle resource sharing & IP integration
> >>> 1. Rework on parent child relation between PWMSS and
> >>> ECAP, EQEP & EHRPWM child devices to support runtime PM.
> >>> 2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
> >>> clock gating from control module.
> >>> 3. Add HWMOD entries for EQEP PWM submodule.
> >>>
> >>
> >> Is there any review on this patch?
> >> This patch depends on ECAP & EHRPWM to work in am335x.
> >
> > First of all, I think you should break up this patch as per the 3 points
> > that you mentioned above.
> >
> > The usage of opt_clks for this does not look right to me. Based on your
> > description this clock is necessary and not optional on AM335x and on
> > Davinci platforms this clock does not exist.

I checked the DA830 TRM and looks like TBCLK for eHRPWM is an always on clock
there. So, the only difference in AM335x is an additional enable bit.

Instead of adding this as opt_clk in hwmod, we could add an always on clock node
in Davinci clock data and have the driver always do a clk_enable() on the tbclk
as part of the probe sequence. On AM335x, with the right clock node this will enable
the clock in hardware and on DA830 it turns into a NOP. This way we can avoid adding
the opt_clk entry in hwmod of eHRPWM.

> >
> > I think the custom activate/deactivate functions in the OMAP runtime PM
> > implementation was a good fit for keeping this SoC integration detail out
> > of the driver code. However, the current DT flow in omap_device.c seems to
> > assign the default activate/deactivate ops. Is that approach deprecated?
>
> The issue is that this approach is not doable anymore with DT, that's
> why I had to provide a default set of functions.
>

So once all OMAP drivers get converted to DT, will there be no notion of
latency based activate/deactivate functions? Or will it get used in a different
manner?

Regards,
Vaibhav

2012-11-27 06:25:32

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH v3 03/10] ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem

On Mon, Nov 26, 2012 at 16:37:36, Bedia, Vaibhav wrote:
> Hi Benoit,
>
> On Mon, Nov 26, 2012 at 14:32:59, Cousson, Benoit wrote:
> > Hi Vaibhav,
> >
> > On 11/26/2012 06:19 AM, Bedia, Vaibhav wrote:
> > > On Fri, Nov 23, 2012 at 16:36:06, Philip, Avinash wrote:
> > >> On Tue, Nov 20, 2012 at 10:33:44, Philip, Avinash wrote:
> > >>> As part of PWM subsystem integration, PWM subsystem are sharing
> > >>> resources like clock across submodules (ECAP, EQEP & EHRPWM).
> > >>> To handle resource sharing & IP integration
> > >>> 1. Rework on parent child relation between PWMSS and
> > >>> ECAP, EQEP & EHRPWM child devices to support runtime PM.
> > >>> 2. Add support for opt_clks in EHRPWM HWMOD entry to handle additional
> > >>> clock gating from control module.
> > >>> 3. Add HWMOD entries for EQEP PWM submodule.
> > >>>
> > >>
> > >> Is there any review on this patch?
> > >> This patch depends on ECAP & EHRPWM to work in am335x.
> > >
> > > First of all, I think you should break up this patch as per the 3 points
> > > that you mentioned above.

I will split the patches into 2.
1. One for correcting hwmod entries plus adding EQEP HWMOD entry
2. Adding parent child relation in hwmod entry.

> > >
> > > The usage of opt_clks for this does not look right to me. Based on your
> > > description this clock is necessary and not optional on AM335x and on
> > > Davinci platforms this clock does not exist.
>
> I checked the DA830 TRM and looks like TBCLK for eHRPWM is an always on clock
> there. So, the only difference in AM335x is an additional enable bit.
>
> Instead of adding this as opt_clk in hwmod, we could add an always on clock node
> in Davinci clock data and have the driver always do a clk_enable() on the tbclk
> as part of the probe sequence. On AM335x, with the right clock node this will enable
> the clock in hardware and on DA830 it turns into a NOP. This way we can avoid adding
> the opt_clk entry in hwmod of eHRPWM.

I will remove opt_clk in HWMOD and made tbclk is a mandatory clock in EHRPWM driver.

Thanks
Avinash