2012-11-05 09:29:23

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 0/8] Support for AM33xx PWM Susbsytem

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 & 6.

Patch #4 & 5 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
- DT node populated in patch #7-8.

This patch series based on linux-next/20121102 and tested on AM335x-evm.
It depends on [1]

1. https://lkml.org/lkml/2012/10/29/589
pwm: Device tree support for PWM polarity

Philip, Avinash (8):
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-tiehrpwm: Add device-tree binding support for EHRPWM driver
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 | 22 +
.../devicetree/bindings/pwm/pwm-tiehrpwm.txt | 25 ++
Documentation/devicetree/bindings/pwm/tipwmss.txt | 30 ++
arch/arm/boot/dts/am335x-evm.dts | 21 +
arch/arm/boot/dts/am33xx.dtsi | 90 +++++
arch/arm/mach-omap2/clock33xx_data.c | 37 ++
arch/arm/mach-omap2/control.h | 8 +
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 414 +++++++++++++-------
drivers/pwm/Kconfig | 11 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-tiecap.c | 36 ++-
drivers/pwm/pwm-tiehrpwm.c | 53 +++-
drivers/pwm/tipwmss.c | 136 +++++++
drivers/pwm/tipwmss.h | 8 +
14 files changed, 754 insertions(+), 138 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/tipwmss.txt
create mode 100644 drivers/pwm/tipwmss.c
create mode 100644 drivers/pwm/tipwmss.h


2012-11-05 09:29:36

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 2/8] 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-05 09:29:46

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 3/8] 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]>
---
:100644 100644 ad8d43b... c419269... M arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 414 +++++++++++++++++++---------
1 files changed, 278 insertions(+), 136 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..c419269 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 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 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 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,210 @@ 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[] = {
+static struct omap_hwmod_addr_space am33xx_ecap0_addr_space[] = {
{
- .pa_start = 0x48302000,
- .pa_end = 0x48302000 + SZ_16 - 1,
+ .pa_start = 0x48300100,
+ .pa_end = 0x48300100 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss0__ecap0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_ecap0_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_ecap0_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_eqep0_addr_space[] = {
{
- .pa_start = 0x48302200,
- .pa_end = 0x48302200 + SZ_256 - 1,
+ .pa_start = 0x48300180,
+ .pa_end = 0x48300180 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
{ }
};

-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__eqep0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_eqep0_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ehrpwm1_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_ehrpwm2_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_ehrpwm0_addr_space[] = {
{
- .pa_start = 0x48304000,
- .pa_end = 0x48304000 + SZ_16 - 1,
+ .pa_start = 0x48300200,
+ .pa_end = 0x48300200 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
+ { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_epwmss0__ehrpwm0 = {
+ .master = &am33xx_epwmss0_hwmod,
+ .slave = &am33xx_ehrpwm0_hwmod,
+ .clk = "l4ls_gclk",
+ .addr = am33xx_ehrpwm0_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am33xx_epwmss1_addr_space[] = {
{
- .pa_start = 0x48304200,
- .pa_end = 0x48304200 + SZ_256 - 1,
+ .pa_start = 0x48302000,
+ .pa_end = 0x48302000 + SZ_16 - 1,
.flags = ADDR_TYPE_RT
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ehrpwm2 = {
+static struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss1 = {
.master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ehrpwm2_hwmod,
+ .slave = &am33xx_epwmss1_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ehrpwm2_addr_space,
+ .addr = am33xx_epwmss1_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_ecap1_addr_space[] = {
{
- .pa_start = 0x48300100,
- .pa_end = 0x48300100 + SZ_256 - 1,
+ .pa_start = 0x48302100,
+ .pa_end = 0x48302100 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
{ }
};

-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_epwmss1__ecap1 = {
+ .master = &am33xx_epwmss1_hwmod,
+ .slave = &am33xx_ecap1_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ecap0_addr_space,
+ .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_ecap1_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_eqep1_addr_space[] = {
{
- .pa_start = 0x48302000,
- .pa_end = 0x48302000 + SZ_16 - 1,
+ .pa_start = 0x48302180,
+ .pa_end = 0x48302180 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
+ { }
+};
+
+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 = 0x48302100,
- .pa_end = 0x48302100 + SZ_256 - 1,
+ .pa_start = 0x48302200,
+ .pa_end = 0x48302200 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
{ }
};

-static struct omap_hwmod_ocp_if am33xx_l4_ls__ecap1 = {
- .master = &am33xx_l4_ls_hwmod,
- .slave = &am33xx_ecap1_hwmod,
+static struct omap_hwmod_ocp_if am33xx_epwmss1__ehrpwm1 = {
+ .master = &am33xx_epwmss1_hwmod,
+ .slave = &am33xx_ehrpwm1_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_ecap1_addr_space,
+ .addr = am33xx_ehrpwm1_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_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,
+ .pa_end = 0x48304100 + SZ_128 - 1,
.flags = ADDR_TYPE_RT
},
{ }
};

-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,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+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,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+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 +3492,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-05 09:30:00

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 4/8] pwm: pwm-tiecap: Add device-tree binding support for APWM driver

Add support for device-tree binding for ECAP APWM driver.
Also size of #pwm-cells set to 3 to support PWM channel number, PWM
period & polarity configuration from device tree.
Also enable clock gating in PWM subsystem common config space.
Also 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]>
---
Second version
- Combined with HWMOD changes & DT bindings.
- Remove the custom of_xlate support.

:000000 100644 0000000... fe24cac... A Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
:100644 100644 d6d4cf0... 7ea5bea2.. M drivers/pwm/pwm-tiecap.c
.../devicetree/bindings/pwm/pwm-tiecap.txt | 22 ++++++++++++
drivers/pwm/pwm-tiecap.c | 36 +++++++++++++++++++-
2 files changed, 57 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..fe24cac
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
@@ -0,0 +1,22 @@
+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 cycle in nanoseconds and bit 0 in the third cell is
+ used to encode the polarity of PWM output.
+- 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..7ea5bea 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -25,6 +25,10 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "tipwmss.h"

/* ECAP registers and bits definitions */
#define CAP1 0x08
@@ -37,6 +41,10 @@
#define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6))
#define ECCTL2_TSCTR_FREERUN BIT(4)

+#define ECAPCLK_EN_SHIFT 0
+
+#define PWM_CELL_SIZE 3
+
struct ecap_pwm_chip {
struct pwm_chip chip;
unsigned int clk_rate;
@@ -184,12 +192,27 @@ static const struct pwm_ops ecap_pwm_ops = {
.owner = THIS_MODULE,
};

+#ifdef CONFIG_OF
+static const struct of_device_id ecap_of_match[] = {
+ {
+ .compatible = "ti,am33xx-ecap",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ecap_of_match);
+#endif
+
static int __devinit ecap_pwm_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
struct clk *clk;
struct ecap_pwm_chip *pc;
+ 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) {
@@ -211,6 +234,7 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)

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

@@ -231,6 +255,10 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)
}

pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ pwmss_submodule_state_change(pdev->dev.parent, ECAPCLK_EN_SHIFT, true);
+ pm_runtime_put_sync(&pdev->dev);
+
platform_set_drvdata(pdev, pc);
return 0;
}
@@ -239,6 +267,10 @@ 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);
+ pwmss_submodule_state_change(pdev->dev.parent, ECAPCLK_EN_SHIFT, false);
+ pm_runtime_put_sync(&pdev->dev);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return pwmchip_remove(&pc->chip);
@@ -246,7 +278,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 = of_match_ptr(ecap_of_match),
},
.probe = ecap_pwm_probe,
.remove = __devexit_p(ecap_pwm_remove),
--
1.7.0.4

2012-11-05 09:30:07

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 5/8] pwm: pwm-tiehrpwm: Add device-tree binding support for EHRPWM driver

Add support for device-tree binding for EHRWPM driver.
Also size of #pwm-cells set to 3 to support PWM channel number, PWM
period & polarity configuration from device tree.
Also enable clock gating in PWM subsystem common config space.
Also 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]>
---
Second version
- Combined with HWMOD changes & DT bindings.
- Remove the custom of_xlate support.

:000000 100644 0000000... aa2ed0a... A Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
:100644 100644 d3c1dff... 1e63652... M drivers/pwm/pwm-tiehrpwm.c
.../devicetree/bindings/pwm/pwm-tiehrpwm.txt | 25 +++++++++++++
drivers/pwm/pwm-tiehrpwm.c | 37 ++++++++++++++++++-
2 files changed, 60 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..aa2ed0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
@@ -0,0 +1,25 @@
+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 cycle in nanoseconds and bit 0 in the third cell is
+ used to encode the polarity of PWM output.
+- 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
+- tbclkgating: platforms require tbclk gating from control module
+ should populate
+
+Example:
+
+ehrpwm0: ehrpwm@0 {
+ compatible = "ti,am33xx-ehrpwm";
+ #pwm-cells = <3>;
+ reg = <0x48300200 0x100>;
+ ti,hwmods = "ehrpwm0";
+ tbclkgating;
+};
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index d3c1dff..1e63652 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -25,6 +25,10 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "tipwmss.h"

/* EHRPWM registers and bits definitions */

@@ -107,6 +111,10 @@
#define AQCSFRC_CSFA_FRCHIGH BIT(1)
#define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0))

+#define EPWMCLK_EN_SHIFT 8
+
+#define PWM_CELL_SIZE 3
+
#define NUM_PWM_CHANNEL 2 /* EHRPWM channels */

struct ehrpwm_pwm_chip {
@@ -392,12 +400,27 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
.owner = THIS_MODULE,
};

+#ifdef CONFIG_OF
+static const struct of_device_id ehrpwm_of_match[] = {
+ {
+ .compatible = "ti,am33xx-ehrpwm",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
+#endif
+
static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
struct clk *clk;
struct ehrpwm_pwm_chip *pc;
+ 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) {
@@ -419,6 +442,7 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)

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

@@ -437,8 +461,11 @@ 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);
+ pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, true);
+ pm_runtime_put_sync(&pdev->dev);
+
platform_set_drvdata(pdev, pc);
return 0;
}
@@ -447,6 +474,10 @@ 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);
+ pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, false);
+ pm_runtime_put_sync(&pdev->dev);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return pwmchip_remove(&pc->chip);
@@ -454,7 +485,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 = of_match_ptr(ehrpwm_of_match),
},
.probe = ehrpwm_pwm_probe,
.remove = __devexit_p(ehrpwm_pwm_remove),
--
1.7.0.4

2012-11-05 09:30:21

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 6/8] pwm: pwm-tiehrpwm: Adding TBCLK gating support.

Some platforms (like AM33XX) requires clock gating from control module
explicitly. So adding optional TBCLK handling if DT node populated with
tbclkgating. This helps the driver can coexist for Davinci platforms.

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

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 1e63652..cf69da3 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -123,6 +123,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)
@@ -461,6 +462,20 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
return ret;
}
+
+ /* Some platforms require explicit tbclk gating */
+ if (of_property_read_bool(pdev->dev.of_node, "tbclkgating")) {
+ pc->tbclk = clk_get(&pdev->dev, "tbclk");
+ if (IS_ERR(pc->tbclk)) {
+ dev_err(&pdev->dev, "Could not get EHRPWM TBCLK\n");
+ return PTR_ERR(pc->tbclk);
+ }
+ }
+
+ /* Enable tbclk & leave */
+ if (pc->tbclk)
+ clk_enable(pc->tbclk);
+
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, true);
@@ -478,6 +493,8 @@ static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev)
pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, false);
pm_runtime_put_sync(&pdev->dev);

+ if (pc->tbclk)
+ clk_disable(pc->tbclk);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return pwmchip_remove(&pc->chip);
--
1.7.0.4

2012-11-05 09:30:37

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 7/8] 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]>
---
Second version
- Combined with HWMOD changes & DT bindings.
- Handling Parent<-> child relation ship for PWM subsystem

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

diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index bb31bff..cf5e049 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -210,5 +210,95 @@
interrupt-parent = <&intc>;
interrupts = <91>;
};
+
+ epwmss0: epwmss@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;
+
+ 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";
+ tbclkgating;
+ };
+ };
+
+ epwmss1: epwmss@48302000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48302000 0x10
+ 0x48302100 0x80
+ 0x48302180 0x80
+ 0x48302200 0x80>;
+ ti,hwmods = "epwmss1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges;
+
+ 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";
+ tbclkgating;
+ };
+ };
+
+ epwmss2: epwmss@48304000 {
+ compatible = "ti,am33xx-pwmss";
+ reg = <0x48304000 0x10
+ 0x48304100 0x80
+ 0x48304180 0x80
+ 0x48304200 0x80>;
+ ti,hwmods = "epwmss2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ ranges;
+
+ 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";
+ tbclkgating;
+ };
+ };
};
};
--
1.7.0.4

2012-11-05 09:30:49

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 8/8] 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]>
---
Second version
- Combined with HWMOD changes & DT bindings.
- No changes

: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-05 09:31:43

by Philip, Avinash

[permalink] [raw]
Subject: [PATCH 1/8] 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]>
---
:000000 100644 0000000... b6c2814... A Documentation/devicetree/bindings/pwm/tipwmss.txt
:100644 100644 ed81720... 99ebcfa... M drivers/pwm/Kconfig
:100644 100644 acfe482... 1001bdb... M drivers/pwm/Makefile
:000000 100644 0000000... d30a802... A drivers/pwm/tipwmss.c
:000000 100644 0000000... 83fdc29... A drivers/pwm/tipwmss.h
Documentation/devicetree/bindings/pwm/tipwmss.txt | 30 +++++
drivers/pwm/Kconfig | 11 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/tipwmss.c | 136 +++++++++++++++++++++
drivers/pwm/tipwmss.h | 8 ++
5 files changed, 186 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/pwm/tipwmss.txt b/Documentation/devicetree/bindings/pwm/tipwmss.txt
new file mode 100644
index 0000000..b6c2814
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/tipwmss.txt
@@ -0,0 +1,30 @@
+TI SOC based PWM Subsystem
+
+Required properties:
+- compatible: Must be "ti,am33xx-pwmss";
+- reg: physical base address and size of the registers map. For am33xx,
+ 4 set of register maps present, PWMSS config space, ECAP register space,
+ EQEP register space, EHRPWM register space.
+- address-cells: Specify the number of u32 entries needed in child nodes.
+ Should set to 1.
+- size-cells: specify inumber 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 empty
+ as parent and child address space is identical.
+
+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 ed81720..99ebcfa 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -125,6 +125,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
@@ -135,6 +136,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
@@ -142,6 +144,15 @@ config PWM_TIEHRPWM
To compile this driver as a module, choose M here: the module
will be called pwm-tiehrpwm.

+config PWM_TIPWMSS
+ tristate "TI PWM Subsytem parent support"
+ 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 acfe482..1001bdb 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.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) += tipwmss.o
obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
diff --git a/drivers/pwm/tipwmss.c b/drivers/pwm/tipwmss.c
new file mode 100644
index 0000000..d30a802
--- /dev/null
+++ b/drivers/pwm/tipwmss.c
@@ -0,0 +1,136 @@
+/*
+ * 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"
+
+struct pwmss_info {
+ void __iomem *mmio_base;
+ struct mutex pwmss_lock;
+};
+
+#define PWMSS_CLKCONFIG 8
+
+void pwmss_submodule_state_change(struct device *dev, int pos, bool enable)
+{
+ struct pwmss_info *info = dev_get_drvdata(dev);
+ u16 val;
+
+ val = readw(info->mmio_base + PWMSS_CLKCONFIG);
+ if (enable)
+ val |= 1 << pos;
+ else
+ val &= ~(1 << pos);
+ mutex_lock(&info->pwmss_lock);
+ writew(val , info->mmio_base + PWMSS_CLKCONFIG);
+ mutex_unlock(&info->pwmss_lock);
+}
+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 __devinit 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_warn(&pdev->dev, "Doesn't have any child node\n");
+
+ return ret;
+}
+
+static int __devexit 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)
+{
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int pwmss_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops pwmss_pm_ops = {
+ .suspend = pwmss_suspend,
+ .resume = pwmss_resume,
+};
+
+static struct platform_driver pwmss_driver = {
+ .driver = {
+ .name = "pwmss",
+ .owner = THIS_MODULE,
+ .pm = &pwmss_pm_ops,
+ .of_match_table = of_match_ptr(pwmss_of_match),
+ },
+ .probe = pwmss_probe,
+ .remove = __devexit_p(pwmss_remove),
+};
+
+module_platform_driver(pwmss_driver);
+
+MODULE_DESCRIPTION("pwmss 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..83fdc29
--- /dev/null
+++ b/drivers/pwm/tipwmss.h
@@ -0,0 +1,8 @@
+#ifdef CONFIG_PWM_TIPWMSS
+extern void pwmss_submodule_state_change(struct device *dev, int pos,
+ bool enable);
+#else
+static inline void pwmss_submodule_state_change(struct device *dev, int pos,
+ bool enable)
+{}
+#endif
--
1.7.0.4

2012-11-06 06:35:55

by Vaibhav Bedia

[permalink] [raw]
Subject: RE: [PATCH 1/8] PWMSS: Add PWM Subsystem driver for parent<->child relationship

On Mon, Nov 05, 2012 at 14:42:22, Philip, Avinash wrote:
[...]
> +pwmss0: pwmss@48300000 {
> + compatible = "ti,am33xx-pwmss";
> + reg = <0x48300000 0x10
> + 0x48300100 0x80
> + 0x48300180 0x80
> + 0x48300200 0x80>;
Do you really need the 4 address ranges here? You eventually do add in
child nodes with other address ranges so isn't the first entry sufficient?
I haven't really looked at the DT details so it is enforced by that let me
know.

[...]
> +
> +#define PWMSS_CLKCONFIG 8
> +

This #def can use a comment.

> +void pwmss_submodule_state_change(struct device *dev, int pos, bool enable)
> +{
> + struct pwmss_info *info = dev_get_drvdata(dev);
> + u16 val;
> +
> + val = readw(info->mmio_base + PWMSS_CLKCONFIG);
> + if (enable)
> + val |= 1 << pos;
> + else
> + val &= ~(1 << pos);
> + mutex_lock(&info->pwmss_lock);
> + writew(val , info->mmio_base + PWMSS_CLKCONFIG);
> + mutex_unlock(&info->pwmss_lock);
> +}
> +EXPORT_SYMBOL(pwmss_submodule_state_change);

I see a clk_en_ack field in the clock status register. You should be checking that.

[...]

> +
> +MODULE_DESCRIPTION("pwmss 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..83fdc29
> --- /dev/null
> +++ b/drivers/pwm/tipwmss.h
> @@ -0,0 +1,8 @@

License text?

> +#ifdef CONFIG_PWM_TIPWMSS
> +extern void pwmss_submodule_state_change(struct device *dev, int pos,
> + bool enable);
> +#else
> +static inline void pwmss_submodule_state_change(struct device *dev, int pos,
> + bool enable)
> +{}
> +#endif

Regards,
Vaibhav

2012-11-06 06:46:35

by Vaibhav Bedia

[permalink] [raw]
Subject: RE: [PATCH 5/8] pwm: pwm-tiehrpwm: Add device-tree binding support for EHRPWM driver

On Mon, Nov 05, 2012 at 14:42:26, Philip, Avinash wrote:
[...]

> +#include <linux/of_device.h>
> +#include <linux/pinctrl/consumer.h>

Pinctrl changes should be separate patch. Morevoer, you don't mention
that you making this change.

> +
> +#include "tipwmss.h"
>
> /* EHRPWM registers and bits definitions */
>
> @@ -107,6 +111,10 @@
> #define AQCSFRC_CSFA_FRCHIGH BIT(1)
> #define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0))
>
> +#define EPWMCLK_EN_SHIFT 8
> +
> +#define PWM_CELL_SIZE 3
> +
> #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */
>
> struct ehrpwm_pwm_chip {
> @@ -392,12 +400,27 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
> .owner = THIS_MODULE,
> };
>
> +#ifdef CONFIG_OF
> +static const struct of_device_id ehrpwm_of_match[] = {
> + {
> + .compatible = "ti,am33xx-ehrpwm",
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
> +#endif
> +
> static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
> {
> int ret;
> struct resource *r;
> struct clk *clk;
> struct ehrpwm_pwm_chip *pc;
> + struct pinctrl *pinctrl;
> +
> + pinctrl = devm_pinctrl_get_select_default(&pdev->dev);

I didn't see a patch adding the pinctrl entries.

> + 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) {
> @@ -419,6 +442,7 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
>
> pc->chip.dev = &pdev->dev;
> pc->chip.ops = &ehrpwm_pwm_ops;
> + pc->chip.of_pwm_n_cells = PWM_CELL_SIZE;
> pc->chip.base = -1;
> pc->chip.npwm = NUM_PWM_CHANNEL;
>
> @@ -437,8 +461,11 @@ 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);
> + pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, true);

I think you should modify this API to return the status for drivers to check.

Another related question, why should this clock be enabled in probe and not only when it
is required? Shouldn't it be disabled in suspend?

Regards,
Vaibhav

2012-11-06 06:46:34

by Vaibhav Bedia

[permalink] [raw]
Subject: RE: [PATCH 6/8] pwm: pwm-tiehrpwm: Adding TBCLK gating support.

On Mon, Nov 05, 2012 at 14:42:27, Philip, Avinash wrote:
[...]

> + /* Some platforms require explicit tbclk gating */
> + if (of_property_read_bool(pdev->dev.of_node, "tbclkgating")) {
> + pc->tbclk = clk_get(&pdev->dev, "tbclk");
> + if (IS_ERR(pc->tbclk)) {
> + dev_err(&pdev->dev, "Could not get EHRPWM TBCLK\n");
> + return PTR_ERR(pc->tbclk);
> + }
> + }
> +
> + /* Enable tbclk & leave */
> + if (pc->tbclk)
> + clk_enable(pc->tbclk);
> +

Here also why are you leaving this clock always running?

Regards,
Vaibhav

2012-11-06 06:46:32

by Vaibhav Bedia

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

On Mon, Nov 05, 2012 at 14:42:29, Philip, Avinash wrote:
[...]

> + am33xx_pinmux: pinmux@44e10800 {
> + ecap0_pins: backlight_pins {
> + pinctrl-single,pins = <
> + 0x164 0x0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
> + >;
> + };
> + };
> +
Ok I see the pinctrl entries here. Shouldn't this be done before
the change in the driver?

Regards.
Vaibhav

2012-11-06 10:09:32

by Vaibhav Bedia

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

On Mon, Nov 05, 2012 at 14:42:24, Philip, Avinash wrote:
[...]

> +
> +static struct omap_hwmod_ocp_if am33xx_epwmss0__ecap0 = {
> + .master = &am33xx_epwmss0_hwmod,
> + .slave = &am33xx_ecap0_hwmod,
> + .clk = "l4ls_gclk",
> + .addr = am33xx_ecap0_addr_space,
> + .user = OCP_USER_MPU,
> +};

Noticed this in another patch which is quite similar so commenting here
again. Is the user field required if you are just creating a parent-child
relationship here?

Regards,
Vaibhav

2012-11-06 13:06:42

by Hiremath, Vaibhav

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

On Tue, Nov 06, 2012 at 15:39:11, Bedia, Vaibhav wrote:
> On Mon, Nov 05, 2012 at 14:42:24, Philip, Avinash wrote:
> [...]
>
> > +
> > +static struct omap_hwmod_ocp_if am33xx_epwmss0__ecap0 = {
> > + .master = &am33xx_epwmss0_hwmod,
> > + .slave = &am33xx_ecap0_hwmod,
> > + .clk = "l4ls_gclk",
> > + .addr = am33xx_ecap0_addr_space,
> > + .user = OCP_USER_MPU,
> > +};
>
> Noticed this in another patch which is quite similar so commenting here
> again. Is the user field required if you are just creating a parent-child
> relationship here?
>

I think user field is not related to parent-child nodes, it defines the initiator to interact with hwmod

Copy-pasted from "arch/arm/plat-omap/include/plat/omap_hwmod.h"

"indicate the initiators that use this interface to interact with the
hwmod"

And in this case, its MPU is the initiator to interact with this interface.


Thanks,
Vaibhav
> Regards,
> Vaibhav
>
>

2012-11-07 15:22:05

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH 1/8] PWMSS: Add PWM Subsystem driver for parent<->child relationship

On Tue, Nov 06, 2012 at 12:05:24, Bedia, Vaibhav wrote:
> On Mon, Nov 05, 2012 at 14:42:22, Philip, Avinash wrote:
> [...]
> > +pwmss0: pwmss@48300000 {
> > + compatible = "ti,am33xx-pwmss";
> > + reg = <0x48300000 0x10
> > + 0x48300100 0x80
> > + 0x48300180 0x80
> > + 0x48300200 0x80>;
> Do you really need the 4 address ranges here? You eventually do add in
> child nodes with other address ranges so isn't the first entry sufficient?
> I haven't really looked at the DT details so it is enforced by that let me
> know.

This is required to define child nodes ranges so that childs reg space
entries are defined in the range.

>
> [...]
> > +
> > +#define PWMSS_CLKCONFIG 8
> > +
>
> This #def can use a comment.

Ok I will add.

>
> > +void pwmss_submodule_state_change(struct device *dev, int pos, bool enable)
> > +{
> > + struct pwmss_info *info = dev_get_drvdata(dev);
> > + u16 val;
> > +
> > + val = readw(info->mmio_base + PWMSS_CLKCONFIG);
> > + if (enable)
> > + val |= 1 << pos;
> > + else
> > + val &= ~(1 << pos);
> > + mutex_lock(&info->pwmss_lock);
> > + writew(val , info->mmio_base + PWMSS_CLKCONFIG);
> > + mutex_unlock(&info->pwmss_lock);
> > +}
> > +EXPORT_SYMBOL(pwmss_submodule_state_change);
>
> I see a clk_en_ack field in the clock status register. You should be checking that.

Ok. I will add for check & return status from pwmss_submodule_state_change().

>
> [...]
>
> > +
> > +MODULE_DESCRIPTION("pwmss 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..83fdc29
> > --- /dev/null
> > +++ b/drivers/pwm/tipwmss.h
> > @@ -0,0 +1,8 @@
>
> License text?

Ok I will add.

Thanks
Avinash
>
> > +#ifdef CONFIG_PWM_TIPWMSS
> > +extern void pwmss_submodule_state_change(struct device *dev, int pos,
> > + bool enable);
> > +#else
> > +static inline void pwmss_submodule_state_change(struct device *dev, int pos,
> > + bool enable)
> > +{}
> > +#endif
>
> Regards,
> Vaibhav
>

2012-11-07 15:22:03

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH 5/8] pwm: pwm-tiehrpwm: Add device-tree binding support for EHRPWM driver

On Tue, Nov 06, 2012 at 12:16:13, Bedia, Vaibhav wrote:
> On Mon, Nov 05, 2012 at 14:42:26, Philip, Avinash wrote:
> [...]
>
> > +#include <linux/of_device.h>
> > +#include <linux/pinctrl/consumer.h>
>
> Pinctrl changes should be separate patch. Morevoer, you don't mention
> that you making this change.

Ok. I will make a separate patch for pinctrl changes.

>
> > +
> > +#include "tipwmss.h"
> >
> > /* EHRPWM registers and bits definitions */
> >
> > @@ -107,6 +111,10 @@
> > #define AQCSFRC_CSFA_FRCHIGH BIT(1)
> > #define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0))
> >
> > +#define EPWMCLK_EN_SHIFT 8
> > +
> > +#define PWM_CELL_SIZE 3
> > +
> > #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */
> >
> > struct ehrpwm_pwm_chip {
> > @@ -392,12 +400,27 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
> > .owner = THIS_MODULE,
> > };
> >
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id ehrpwm_of_match[] = {
> > + {
> > + .compatible = "ti,am33xx-ehrpwm",
> > + },
> > + {},
> > +};
> > +MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
> > +#endif
> > +
> > static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
> > {
> > int ret;
> > struct resource *r;
> > struct clk *clk;
> > struct ehrpwm_pwm_chip *pc;
> > + struct pinctrl *pinctrl;
> > +
> > + pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
>
> I didn't see a patch adding the pinctrl entries.

Patch 8/8 has pinctrl entries in DT. First driver changes for supporting
DT data.

>
> > + 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) {
> > @@ -419,6 +442,7 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
> >
> > pc->chip.dev = &pdev->dev;
> > pc->chip.ops = &ehrpwm_pwm_ops;
> > + pc->chip.of_pwm_n_cells = PWM_CELL_SIZE;
> > pc->chip.base = -1;
> > pc->chip.npwm = NUM_PWM_CHANNEL;
> >
> > @@ -437,8 +461,11 @@ 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);
> > + pwmss_submodule_state_change(pdev->dev.parent, EPWMCLK_EN_SHIFT, true);
>
> I think you should modify this API to return the status for drivers to check.

Check for status check will add.

>
> Another related question, why should this clock be enabled in probe and not only when it
> is required?

This is another clock gating from PWM subsystem as all sub modules shared the clock resource.
Still this gating from PWM subsystem is required to access PWM sub modules.
Handling of this for context loss & restore done at pwmss driver, will add the support.

> Shouldn't it be disabled in suspend?

Will take care when adding suspend/resume functionality.

Thanks
Avinash

>
> Regards,
> Vaibhav
>

2012-11-07 15:22:01

by Philip, Avinash

[permalink] [raw]
Subject: RE: [PATCH 6/8] pwm: pwm-tiehrpwm: Adding TBCLK gating support.

On Tue, Nov 06, 2012 at 12:16:13, Bedia, Vaibhav wrote:
> On Mon, Nov 05, 2012 at 14:42:27, Philip, Avinash wrote:
> [...]
>
> > + /* Some platforms require explicit tbclk gating */
> > + if (of_property_read_bool(pdev->dev.of_node, "tbclkgating")) {
> > + pc->tbclk = clk_get(&pdev->dev, "tbclk");
> > + if (IS_ERR(pc->tbclk)) {
> > + dev_err(&pdev->dev, "Could not get EHRPWM TBCLK\n");
> > + return PTR_ERR(pc->tbclk);
> > + }
> > + }
> > +
> > + /* Enable tbclk & leave */
> > + if (pc->tbclk)
> > + clk_enable(pc->tbclk);
> > +
>
> Here also why are you leaving this clock always running?

This is an additional clock gating for EHRPWM functional clock from
control module. The enabling of this clock to pwm_enable
& disabling to pwm_disable. I will correct it.



Thanks
Avinash

>
> Regards,
> Vaibhav
>