]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'next/devel2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Jul 2011 00:42:18 +0000 (17:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Jul 2011 00:42:18 +0000 (17:42 -0700)
* 'next/devel2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc: (47 commits)
  OMAP: Add debugfs node to show the summary of all clocks
  OMAP2+: hwmod: Follow the recommended PRCM module enable sequence
  OMAP2+: clock: allow per-SoC clock init code to prevent clockdomain calls from clock code
  OMAP2+: clockdomain: Add per clkdm lock to prevent concurrent state programming
  OMAP2+: PM: idle clkdms only if already in idle
  OMAP2+: clockdomain: add clkdm_in_hwsup()
  OMAP2+: clockdomain: Add 2 APIs to control clockdomain from hwmod framework
  OMAP: clockdomain: Remove redundant call to pwrdm_wait_transition()
  OMAP4: hwmod: Introduce the module control in hwmod control
  OMAP4: cm: Add two new APIs for modulemode control
  OMAP4: hwmod data: Add modulemode entry in omap_hwmod structure
  OMAP4: hwmod data: Add PRM context register offset
  OMAP4: prm: Remove deprecated functions
  OMAP4: prm: Replace warm reset API with the offset based version
  OMAP4: hwmod: Replace RSTCTRL absolute address with offset macros
  OMAP: hwmod: Wait the idle status to be disabled
  OMAP4: hwmod: Replace CLKCTRL absolute address with offset macros
  OMAP2+: hwmod: Init clkdm field at boot time
  OMAP4: hwmod data: Add clock domain attribute
  OMAP4: clock data: Add missing divider selection for auxclks
  ...

51 files changed:
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
arch/arm/mach-omap2/clockdomain44xx.c
arch/arm/mach-omap2/clockdomains44xx_data.c
arch/arm/mach-omap2/cm44xx.h
arch/arm/mach-omap2/cminst44xx.c
arch/arm/mach-omap2/cminst44xx.h
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/prcm.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm44xx.h
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-omap2/prminst44xx.h
arch/arm/mach-omap2/twl-common.c
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/plat-omap/include/plat/omap_hwmod.h
arch/arm/plat-omap/omap_device.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/twl4030-vibra.c
drivers/input/misc/twl6040-vibra.c [new file with mode: 0644]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/twl-core.c
drivers/mfd/twl4030-audio.c [new file with mode: 0644]
drivers/mfd/twl4030-codec.c [deleted file]
drivers/mfd/twl6040-core.c [new file with mode: 0644]
drivers/mfd/twl6040-irq.c [new file with mode: 0644]
include/linux/i2c/twl.h
include/linux/mfd/twl4030-audio.h [moved from include/linux/mfd/twl4030-codec.h with 96% similarity]
include/linux/mfd/twl6040.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/twl6040.h
sound/soc/omap/sdp3430.c
sound/soc/omap/sdp4430.c
sound/soc/omap/zoom2.c

index a7c0b31fd0849930a71141aae1bb8a1c3587f0b5..c7cef44c75d4e3df3753e1693ecd2835fadcc5c2 100644 (file)
@@ -345,11 +345,40 @@ static struct platform_device sdp4430_lcd_device = {
        .id             = -1,
 };
 
+static struct regulator_consumer_supply sdp4430_vbat_supply[] = {
+       REGULATOR_SUPPLY("vddvibl", "twl6040-vibra"),
+       REGULATOR_SUPPLY("vddvibr", "twl6040-vibra"),
+};
+
+static struct regulator_init_data sdp4430_vbat_data = {
+       .constraints = {
+               .always_on      = 1,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(sdp4430_vbat_supply),
+       .consumer_supplies      = sdp4430_vbat_supply,
+};
+
+static struct fixed_voltage_config sdp4430_vbat_pdata = {
+       .supply_name    = "VBAT",
+       .microvolts     = 3750000,
+       .init_data      = &sdp4430_vbat_data,
+       .gpio           = -EINVAL,
+};
+
+static struct platform_device sdp4430_vbat = {
+       .name           = "reg-fixed-voltage",
+       .id             = -1,
+       .dev = {
+               .platform_data = &sdp4430_vbat_pdata,
+       },
+};
+
 static struct platform_device *sdp4430_devices[] __initdata = {
        &sdp4430_lcd_device,
        &sdp4430_gpio_keys_device,
        &sdp4430_leds_gpio,
        &sdp4430_leds_pwm,
+       &sdp4430_vbat,
 };
 
 static struct omap_lcd_config sdp4430_lcd_config __initdata = {
@@ -505,7 +534,33 @@ static struct regulator_init_data sdp4430_vusim = {
        },
 };
 
+static struct twl4030_codec_data twl6040_codec = {
+       /* single-step ramp for headset and handsfree */
+       .hs_left_step   = 0x0f,
+       .hs_right_step  = 0x0f,
+       .hf_left_step   = 0x1d,
+       .hf_right_step  = 0x1d,
+};
+
+static struct twl4030_vibra_data twl6040_vibra = {
+       .vibldrv_res = 8,
+       .vibrdrv_res = 3,
+       .viblmotor_res = 10,
+       .vibrmotor_res = 10,
+       .vddvibl_uV = 0,        /* fixed volt supply - VBAT */
+       .vddvibr_uV = 0,        /* fixed volt supply - VBAT */
+};
+
+static struct twl4030_audio_data twl6040_audio = {
+       .codec          = &twl6040_codec,
+       .vibra          = &twl6040_vibra,
+       .audpwron_gpio  = 127,
+       .naudint_irq    = OMAP44XX_IRQ_SYS_2N,
+       .irq_base       = TWL6040_CODEC_IRQ_BASE,
+};
+
 static struct twl4030_platform_data sdp4430_twldata = {
+       .audio          = &twl6040_audio,
        /* Regulators */
        .vusim          = &sdp4430_vusim,
        .vaux1          = &sdp4430_vaux1,
index 0c9e0f28ed0738d5782e1dd328f9a34f4dcb2054..cc503aa89c5e3685b6cc5901a2329a67c6926d99 100644 (file)
@@ -864,11 +864,11 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
        .resource_config = twl4030_rconfig,
 };
 
-struct twl4030_codec_vibra_data rx51_vibra_data __initdata = {
+struct twl4030_vibra_data rx51_vibra_data __initdata = {
        .coexist        = 0,
 };
 
-struct twl4030_codec_data rx51_codec_data __initdata = {
+struct twl4030_audio_data rx51_audio_data __initdata = {
        .audio_mclk     = 26000000,
        .vibra          = &rx51_vibra_data,
 };
@@ -878,7 +878,7 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
        .gpio                   = &rx51_gpio_data,
        .keypad                 = &rx51_kp_data,
        .power                  = &rx51_t2scripts_data,
-       .codec                  = &rx51_codec_data,
+       .audio                  = &rx51_audio_data,
 
        .vaux1                  = &rx51_vaux1,
        .vaux2                  = &rx51_vaux2,
index 13a644233667d9ee54995d018d6eb044bde808d7..6d0aa4fcb7c37fed33337732b41ab35fda62f22d 100644 (file)
@@ -274,12 +274,12 @@ static int __init omap_i2c_init(void)
                        TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
 
        if (machine_is_omap_zoom2()) {
-               struct twl4030_codec_audio_data *audio_data;
-               audio_data = zoom_twldata.codec->audio;
+               struct twl4030_codec_data *codec_data;
+               codec_data = zoom_twldata.audio->codec;
 
-               audio_data->ramp_delay_value = 3;       /* 161 ms */
-               audio_data->hs_extmute = 1;
-               audio_data->set_hs_extmute = zoom2_set_hs_extmute;
+               codec_data->ramp_delay_value = 3;       /* 161 ms */
+               codec_data->hs_extmute = 1;
+               codec_data->set_hs_extmute = zoom2_set_hs_extmute;
        }
        omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
index bf9c36c7dffd55d073702597dd8e95f31544207d..1f3481f8d695f73a71bf8725eba18ca4c702a58e 100644 (file)
 
 u8 cpu_mask;
 
+/*
+ * clkdm_control: if true, then when a clock is enabled in the
+ * hardware, its clockdomain will first be enabled; and when a clock
+ * is disabled in the hardware, its clockdomain will be disabled
+ * afterwards.
+ */
+static bool clkdm_control = true;
+
 /*
  * OMAP2+ specific clock functions
  */
@@ -99,6 +107,19 @@ void omap2_init_clk_clkdm(struct clk *clk)
        }
 }
 
+/**
+ * omap2_clk_disable_clkdm_control - disable clkdm control on clk enable/disable
+ *
+ * Prevent the OMAP clock code from calling into the clockdomain code
+ * when a hardware clock in that clockdomain is enabled or disabled.
+ * Intended to be called at init time from omap*_clk_init().  No
+ * return value.
+ */
+void __init omap2_clk_disable_clkdm_control(void)
+{
+       clkdm_control = false;
+}
+
 /**
  * omap2_clk_dflt_find_companion - find companion clock to @clk
  * @clk: struct clk * to find the companion clock of
@@ -268,7 +289,7 @@ void omap2_clk_disable(struct clk *clk)
                clk->ops->disable(clk);
        }
 
-       if (clk->clkdm)
+       if (clkdm_control && clk->clkdm)
                clkdm_clk_disable(clk->clkdm, clk);
 
        if (clk->parent)
@@ -308,7 +329,7 @@ int omap2_clk_enable(struct clk *clk)
                }
        }
 
-       if (clk->clkdm) {
+       if (clkdm_control && clk->clkdm) {
                ret = clkdm_clk_enable(clk->clkdm, clk);
                if (ret) {
                        WARN(1, "clock: %s: could not enable clockdomain %s: "
@@ -330,7 +351,7 @@ int omap2_clk_enable(struct clk *clk)
        return 0;
 
 oce_err3:
-       if (clk->clkdm)
+       if (clkdm_control && clk->clkdm)
                clkdm_clk_disable(clk->clkdm, clk);
 oce_err2:
        if (clk->parent)
index e10ff2b5484430d9cc083890023dc775c4a42599..48ac568881bd4de531808d092356b440687b9fee 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H
 #define __ARCH_ARM_MACH_OMAP2_CLOCK_H
 
+#include <linux/kernel.h>
+
 #include <plat/clock.h>
 
 /* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
@@ -72,6 +74,7 @@ void omap2_clk_disable_unused(struct clk *clk);
 #endif
 
 void omap2_init_clk_clkdm(struct clk *clk);
+void __init omap2_clk_disable_clkdm_control(void);
 
 /* clkt_clksel.c public functions */
 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
index 2926d028b6e906094a7b4df7fb1402951b06a479..debc040872f1b14940204c14def09a7081117c8e 100644 (file)
@@ -1805,9 +1805,9 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "gfx_ick",      &gfx_ick,       CK_242X),
        /* DSS domain clocks */
        CLK("omapdss_dss",      "ick",          &dss_ick,       CK_242X),
-       CLK("omapdss_dss",      "fck",          &dss1_fck,      CK_242X),
-       CLK("omapdss_dss",      "sys_clk",      &dss2_fck,      CK_242X),
-       CLK("omapdss_dss",      "tv_clk",       &dss_54m_fck,   CK_242X),
+       CLK(NULL,       "dss1_fck",             &dss1_fck,      CK_242X),
+       CLK(NULL,       "dss2_fck",     &dss2_fck,      CK_242X),
+       CLK(NULL,       "dss_54m_fck",  &dss_54m_fck,   CK_242X),
        /* L3 domain clocks */
        CLK(NULL,       "core_l3_ck",   &core_l3_ck,    CK_242X),
        CLK(NULL,       "ssi_fck",      &ssi_ssr_sst_fck, CK_242X),
@@ -1844,13 +1844,13 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "gpt12_ick",    &gpt12_ick,     CK_242X),
        CLK(NULL,       "gpt12_fck",    &gpt12_fck,     CK_242X),
        CLK("omap-mcbsp.1", "ick",      &mcbsp1_ick,    CK_242X),
-       CLK("omap-mcbsp.1", "fck",      &mcbsp1_fck,    CK_242X),
+       CLK(NULL,       "mcbsp1_fck",   &mcbsp1_fck,    CK_242X),
        CLK("omap-mcbsp.2", "ick",      &mcbsp2_ick,    CK_242X),
-       CLK("omap-mcbsp.2", "fck",      &mcbsp2_fck,    CK_242X),
+       CLK(NULL,       "mcbsp2_fck",   &mcbsp2_fck,    CK_242X),
        CLK("omap2_mcspi.1", "ick",     &mcspi1_ick,    CK_242X),
-       CLK("omap2_mcspi.1", "fck",     &mcspi1_fck,    CK_242X),
+       CLK(NULL,       "mcspi1_fck",   &mcspi1_fck,    CK_242X),
        CLK("omap2_mcspi.2", "ick",     &mcspi2_ick,    CK_242X),
-       CLK("omap2_mcspi.2", "fck",     &mcspi2_fck,    CK_242X),
+       CLK(NULL,       "mcspi2_fck",   &mcspi2_fck,    CK_242X),
        CLK(NULL,       "uart1_ick",    &uart1_ick,     CK_242X),
        CLK(NULL,       "uart1_fck",    &uart1_fck,     CK_242X),
        CLK(NULL,       "uart2_ick",    &uart2_ick,     CK_242X),
@@ -1860,7 +1860,7 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "gpios_ick",    &gpios_ick,     CK_242X),
        CLK(NULL,       "gpios_fck",    &gpios_fck,     CK_242X),
        CLK("omap_wdt", "ick",          &mpu_wdt_ick,   CK_242X),
-       CLK("omap_wdt", "fck",          &mpu_wdt_fck,   CK_242X),
+       CLK(NULL,       "mpu_wdt_fck",  &mpu_wdt_fck,   CK_242X),
        CLK(NULL,       "sync_32k_ick", &sync_32k_ick,  CK_242X),
        CLK(NULL,       "wdt1_ick",     &wdt1_ick,      CK_242X),
        CLK(NULL,       "omapctrl_ick", &omapctrl_ick,  CK_242X),
@@ -1880,11 +1880,11 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "eac_ick",      &eac_ick,       CK_242X),
        CLK(NULL,       "eac_fck",      &eac_fck,       CK_242X),
        CLK("omap_hdq.0", "ick",        &hdq_ick,       CK_242X),
-       CLK("omap_hdq.1", "fck",        &hdq_fck,       CK_242X),
+       CLK("omap_hdq.0", "fck",        &hdq_fck,       CK_242X),
        CLK("omap_i2c.1", "ick",        &i2c1_ick,      CK_242X),
-       CLK("omap_i2c.1", "fck",        &i2c1_fck,      CK_242X),
+       CLK(NULL,       "i2c1_fck",     &i2c1_fck,      CK_242X),
        CLK("omap_i2c.2", "ick",        &i2c2_ick,      CK_242X),
-       CLK("omap_i2c.2", "fck",        &i2c2_fck,      CK_242X),
+       CLK(NULL,       "i2c2_fck",     &i2c2_fck,      CK_242X),
        CLK(NULL,       "gpmc_fck",     &gpmc_fck,      CK_242X),
        CLK(NULL,       "sdma_fck",     &sdma_fck,      CK_242X),
        CLK(NULL,       "sdma_ick",     &sdma_ick,      CK_242X),
index 0c79d39e3021f02f59f54ab9aedfd9e10942e44e..96a942e42db197facb0ce1b4348a3806cb22f310 100644 (file)
@@ -1895,9 +1895,9 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "mdm_osc_ck",   &mdm_osc_ck,    CK_243X),
        /* DSS domain clocks */
        CLK("omapdss_dss",      "ick",          &dss_ick,       CK_243X),
-       CLK("omapdss_dss",      "fck",          &dss1_fck,      CK_243X),
-       CLK("omapdss_dss",      "sys_clk",      &dss2_fck,      CK_243X),
-       CLK("omapdss_dss",      "tv_clk",       &dss_54m_fck,   CK_243X),
+       CLK(NULL,       "dss1_fck",             &dss1_fck,      CK_243X),
+       CLK(NULL,       "dss2_fck",     &dss2_fck,      CK_243X),
+       CLK(NULL,       "dss_54m_fck",  &dss_54m_fck,   CK_243X),
        /* L3 domain clocks */
        CLK(NULL,       "core_l3_ck",   &core_l3_ck,    CK_243X),
        CLK(NULL,       "ssi_fck",      &ssi_ssr_sst_fck, CK_243X),
@@ -1934,21 +1934,21 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "gpt12_ick",    &gpt12_ick,     CK_243X),
        CLK(NULL,       "gpt12_fck",    &gpt12_fck,     CK_243X),
        CLK("omap-mcbsp.1", "ick",      &mcbsp1_ick,    CK_243X),
-       CLK("omap-mcbsp.1", "fck",      &mcbsp1_fck,    CK_243X),
+       CLK(NULL,       "mcbsp1_fck",   &mcbsp1_fck,    CK_243X),
        CLK("omap-mcbsp.2", "ick",      &mcbsp2_ick,    CK_243X),
-       CLK("omap-mcbsp.2", "fck",      &mcbsp2_fck,    CK_243X),
+       CLK(NULL,       "mcbsp2_fck",   &mcbsp2_fck,    CK_243X),
        CLK("omap-mcbsp.3", "ick",      &mcbsp3_ick,    CK_243X),
-       CLK("omap-mcbsp.3", "fck",      &mcbsp3_fck,    CK_243X),
+       CLK(NULL,       "mcbsp3_fck",   &mcbsp3_fck,    CK_243X),
        CLK("omap-mcbsp.4", "ick",      &mcbsp4_ick,    CK_243X),
-       CLK("omap-mcbsp.4", "fck",      &mcbsp4_fck,    CK_243X),
+       CLK(NULL,       "mcbsp4_fck",   &mcbsp4_fck,    CK_243X),
        CLK("omap-mcbsp.5", "ick",      &mcbsp5_ick,    CK_243X),
-       CLK("omap-mcbsp.5", "fck",      &mcbsp5_fck,    CK_243X),
+       CLK(NULL,       "mcbsp5_fck",   &mcbsp5_fck,    CK_243X),
        CLK("omap2_mcspi.1", "ick",     &mcspi1_ick,    CK_243X),
-       CLK("omap2_mcspi.1", "fck",     &mcspi1_fck,    CK_243X),
+       CLK(NULL,       "mcspi1_fck",   &mcspi1_fck,    CK_243X),
        CLK("omap2_mcspi.2", "ick",     &mcspi2_ick,    CK_243X),
-       CLK("omap2_mcspi.2", "fck",     &mcspi2_fck,    CK_243X),
+       CLK(NULL,       "mcspi2_fck",   &mcspi2_fck,    CK_243X),
        CLK("omap2_mcspi.3", "ick",     &mcspi3_ick,    CK_243X),
-       CLK("omap2_mcspi.3", "fck",     &mcspi3_fck,    CK_243X),
+       CLK(NULL,       "mcspi3_fck",   &mcspi3_fck,    CK_243X),
        CLK(NULL,       "uart1_ick",    &uart1_ick,     CK_243X),
        CLK(NULL,       "uart1_fck",    &uart1_fck,     CK_243X),
        CLK(NULL,       "uart2_ick",    &uart2_ick,     CK_243X),
@@ -1958,7 +1958,7 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "gpios_ick",    &gpios_ick,     CK_243X),
        CLK(NULL,       "gpios_fck",    &gpios_fck,     CK_243X),
        CLK("omap_wdt", "ick",          &mpu_wdt_ick,   CK_243X),
-       CLK("omap_wdt", "fck",          &mpu_wdt_fck,   CK_243X),
+       CLK(NULL,       "mpu_wdt_fck",  &mpu_wdt_fck,   CK_243X),
        CLK(NULL,       "sync_32k_ick", &sync_32k_ick,  CK_243X),
        CLK(NULL,       "wdt1_ick",     &wdt1_ick,      CK_243X),
        CLK(NULL,       "omapctrl_ick", &omapctrl_ick,  CK_243X),
@@ -1975,9 +1975,9 @@ static struct omap_clk omap2430_clks[] = {
        CLK("omap_hdq.0", "ick",        &hdq_ick,       CK_243X),
        CLK("omap_hdq.1", "fck",        &hdq_fck,       CK_243X),
        CLK("omap_i2c.1", "ick",        &i2c1_ick,      CK_243X),
-       CLK("omap_i2c.1", "fck",        &i2chs1_fck,    CK_243X),
+       CLK(NULL,       "i2chs1_fck",   &i2chs1_fck,    CK_243X),
        CLK("omap_i2c.2", "ick",        &i2c2_ick,      CK_243X),
-       CLK("omap_i2c.2", "fck",        &i2chs2_fck,    CK_243X),
+       CLK(NULL,       "i2chs2_fck",   &i2chs2_fck,    CK_243X),
        CLK(NULL,       "gpmc_fck",     &gpmc_fck,      CK_243X),
        CLK(NULL,       "sdma_fck",     &sdma_fck,      CK_243X),
        CLK(NULL,       "sdma_ick",     &sdma_ick,      CK_243X),
@@ -1990,9 +1990,9 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "usb_fck",      &usb_fck,       CK_243X),
        CLK("musb-omap2430",    "ick",  &usbhs_ick,     CK_243X),
        CLK("omap_hsmmc.0", "ick",      &mmchs1_ick,    CK_243X),
-       CLK("omap_hsmmc.0", "fck",      &mmchs1_fck,    CK_243X),
+       CLK(NULL,       "mmchs1_fck",   &mmchs1_fck,    CK_243X),
        CLK("omap_hsmmc.1", "ick",      &mmchs2_ick,    CK_243X),
-       CLK("omap_hsmmc.1", "fck",      &mmchs2_fck,    CK_243X),
+       CLK(NULL,       "mmchs2_fck",   &mmchs2_fck,    CK_243X),
        CLK(NULL,       "gpio5_ick",    &gpio5_ick,     CK_243X),
        CLK(NULL,       "gpio5_fck",    &gpio5_fck,     CK_243X),
        CLK(NULL,       "mdm_intc_ick", &mdm_intc_ick,  CK_243X),
index 75b119bd9cda8cf313cf4df080e26703ddb9a498..ffd55b1c439622002be65a320957c943a7b19a18 100644 (file)
@@ -3289,25 +3289,25 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK("omap-mcbsp.1",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
        CLK("omap-mcbsp.5",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
        CLK(NULL,       "core_96m_fck", &core_96m_fck,  CK_3XXX),
-       CLK("omap_hsmmc.2",     "fck",  &mmchs3_fck,    CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-       CLK("omap_hsmmc.1",     "fck",  &mmchs2_fck,    CK_3XXX),
+       CLK(NULL,       "mmchs3_fck",   &mmchs3_fck,    CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+       CLK(NULL,       "mmchs2_fck",   &mmchs2_fck,    CK_3XXX),
        CLK(NULL,       "mspro_fck",    &mspro_fck,     CK_34XX | CK_36XX),
-       CLK("omap_hsmmc.0",     "fck",  &mmchs1_fck,    CK_3XXX),
-       CLK("omap_i2c.3", "fck",        &i2c3_fck,      CK_3XXX),
-       CLK("omap_i2c.2", "fck",        &i2c2_fck,      CK_3XXX),
-       CLK("omap_i2c.1", "fck",        &i2c1_fck,      CK_3XXX),
-       CLK("omap-mcbsp.5", "fck",      &mcbsp5_fck,    CK_3XXX),
-       CLK("omap-mcbsp.1", "fck",      &mcbsp1_fck,    CK_3XXX),
+       CLK(NULL,       "mmchs1_fck",   &mmchs1_fck,    CK_3XXX),
+       CLK(NULL,       "i2c3_fck",     &i2c3_fck,      CK_3XXX),
+       CLK(NULL,       "i2c2_fck",     &i2c2_fck,      CK_3XXX),
+       CLK(NULL,       "i2c1_fck",     &i2c1_fck,      CK_3XXX),
+       CLK(NULL,       "mcbsp5_fck",   &mcbsp5_fck,    CK_3XXX),
+       CLK(NULL,       "mcbsp1_fck",   &mcbsp1_fck,    CK_3XXX),
        CLK(NULL,       "core_48m_fck", &core_48m_fck,  CK_3XXX),
-       CLK("omap2_mcspi.4", "fck",     &mcspi4_fck,    CK_3XXX),
-       CLK("omap2_mcspi.3", "fck",     &mcspi3_fck,    CK_3XXX),
-       CLK("omap2_mcspi.2", "fck",     &mcspi2_fck,    CK_3XXX),
-       CLK("omap2_mcspi.1", "fck",     &mcspi1_fck,    CK_3XXX),
+       CLK(NULL,       "mcspi4_fck",   &mcspi4_fck,    CK_3XXX),
+       CLK(NULL,       "mcspi3_fck",   &mcspi3_fck,    CK_3XXX),
+       CLK(NULL,       "mcspi2_fck",   &mcspi2_fck,    CK_3XXX),
+       CLK(NULL,       "mcspi1_fck",   &mcspi1_fck,    CK_3XXX),
        CLK(NULL,       "uart2_fck",    &uart2_fck,     CK_3XXX),
        CLK(NULL,       "uart1_fck",    &uart1_fck,     CK_3XXX),
        CLK(NULL,       "fshostusb_fck", &fshostusb_fck, CK_3430ES1),
        CLK(NULL,       "core_12m_fck", &core_12m_fck,  CK_3XXX),
-       CLK("omap_hdq.0", "fck",        &hdq_fck,       CK_3XXX),
+       CLK("omap_hdq.0",       "fck",  &hdq_fck,       CK_3XXX),
        CLK(NULL,       "ssi_ssr_fck",  &ssi_ssr_fck_3430es1,   CK_3430ES1),
        CLK(NULL,       "ssi_ssr_fck",  &ssi_ssr_fck_3430es2,   CK_3430ES2PLUS | CK_36XX),
        CLK(NULL,       "ssi_sst_fck",  &ssi_sst_fck_3430es1,   CK_3430ES1),
@@ -3356,11 +3356,11 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK("omap_rng", "ick",          &rng_ick,       CK_34XX | CK_36XX),
        CLK(NULL,       "sha11_ick",    &sha11_ick,     CK_34XX | CK_36XX),
        CLK(NULL,       "des1_ick",     &des1_ick,      CK_34XX | CK_36XX),
-       CLK("omapdss_dss",      "fck",          &dss1_alwon_fck_3430es1, CK_3430ES1),
-       CLK("omapdss_dss",      "fck",          &dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-       CLK("omapdss_dss",      "tv_clk",       &dss_tv_fck,    CK_3XXX),
-       CLK("omapdss_dss",      "video_clk",    &dss_96m_fck,   CK_3XXX),
-       CLK("omapdss_dss",      "sys_clk",      &dss2_alwon_fck, CK_3XXX),
+       CLK(NULL,       "dss1_alwon_fck",               &dss1_alwon_fck_3430es1, CK_3430ES1),
+       CLK(NULL,       "dss1_alwon_fck",               &dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+       CLK(NULL,       "dss_tv_fck",   &dss_tv_fck,    CK_3XXX),
+       CLK(NULL,       "dss_96m_fck",  &dss_96m_fck,   CK_3XXX),
+       CLK(NULL,       "dss2_alwon_fck",       &dss2_alwon_fck, CK_3XXX),
        CLK("omapdss_dss",      "ick",          &dss_ick_3430es1,       CK_3430ES1),
        CLK("omapdss_dss",      "ick",          &dss_ick_3430es2,       CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
        CLK(NULL,       "cam_mclk",     &cam_mclk,      CK_34XX | CK_36XX),
@@ -3385,7 +3385,7 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "gpt1_fck",     &gpt1_fck,      CK_3XXX),
        CLK(NULL,       "wkup_32k_fck", &wkup_32k_fck,  CK_3XXX),
        CLK(NULL,       "gpio1_dbck",   &gpio1_dbck,    CK_3XXX),
-       CLK("omap_wdt", "fck",          &wdt2_fck,      CK_3XXX),
+       CLK(NULL,       "wdt2_fck",             &wdt2_fck,      CK_3XXX),
        CLK(NULL,       "wkup_l4_ick",  &wkup_l4_ick,   CK_34XX | CK_36XX),
        CLK(NULL,       "usim_ick",     &usim_ick,      CK_3430ES2PLUS | CK_36XX),
        CLK("omap_wdt", "ick",          &wdt2_ick,      CK_3XXX),
@@ -3436,9 +3436,9 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK("omap-mcbsp.2", "ick",      &mcbsp2_ick,    CK_3XXX),
        CLK("omap-mcbsp.3", "ick",      &mcbsp3_ick,    CK_3XXX),
        CLK("omap-mcbsp.4", "ick",      &mcbsp4_ick,    CK_3XXX),
-       CLK("omap-mcbsp.2", "fck",      &mcbsp2_fck,    CK_3XXX),
-       CLK("omap-mcbsp.3", "fck",      &mcbsp3_fck,    CK_3XXX),
-       CLK("omap-mcbsp.4", "fck",      &mcbsp4_fck,    CK_3XXX),
+       CLK(NULL,       "mcbsp2_fck",   &mcbsp2_fck,    CK_3XXX),
+       CLK(NULL,       "mcbsp3_fck",   &mcbsp3_fck,    CK_3XXX),
+       CLK(NULL,       "mcbsp4_fck",   &mcbsp4_fck,    CK_3XXX),
        CLK("etb",      "emu_src_ck",   &emu_src_ck,    CK_3XXX),
        CLK(NULL,       "pclk_fck",     &pclk_fck,      CK_3XXX),
        CLK(NULL,       "pclkx2_fck",   &pclkx2_fck,    CK_3XXX),
index 25473a1db3e759fe2761b051fd2b6374161396c9..2af0e3f00ce1b509fe09fbd396b912026ca0d161 100644 (file)
@@ -2808,19 +2808,39 @@ static struct clk trace_clk_div_ck = {
 
 /* SCRM aux clk nodes */
 
-static const struct clksel auxclk_sel[] = {
+static const struct clksel auxclk_src_sel[] = {
        { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
        { .parent = &dpll_core_m3x2_ck, .rates = div_1_1_rates },
        { .parent = &dpll_per_m3x2_ck, .rates = div_1_2_rates },
        { .parent = NULL },
 };
 
-static struct clk auxclk0_ck = {
-       .name           = "auxclk0_ck",
+static const struct clksel_rate div16_1to16_rates[] = {
+       { .div = 1, .val = 0, .flags = RATE_IN_4430 },
+       { .div = 2, .val = 1, .flags = RATE_IN_4430 },
+       { .div = 3, .val = 2, .flags = RATE_IN_4430 },
+       { .div = 4, .val = 3, .flags = RATE_IN_4430 },
+       { .div = 5, .val = 4, .flags = RATE_IN_4430 },
+       { .div = 6, .val = 5, .flags = RATE_IN_4430 },
+       { .div = 7, .val = 6, .flags = RATE_IN_4430 },
+       { .div = 8, .val = 7, .flags = RATE_IN_4430 },
+       { .div = 9, .val = 8, .flags = RATE_IN_4430 },
+       { .div = 10, .val = 9, .flags = RATE_IN_4430 },
+       { .div = 11, .val = 10, .flags = RATE_IN_4430 },
+       { .div = 12, .val = 11, .flags = RATE_IN_4430 },
+       { .div = 13, .val = 12, .flags = RATE_IN_4430 },
+       { .div = 14, .val = 13, .flags = RATE_IN_4430 },
+       { .div = 15, .val = 14, .flags = RATE_IN_4430 },
+       { .div = 16, .val = 15, .flags = RATE_IN_4430 },
+       { .div = 0 },
+};
+
+static struct clk auxclk0_src_ck = {
+       .name           = "auxclk0_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK0,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2828,12 +2848,29 @@ static struct clk auxclk0_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
-static struct clk auxclk1_ck = {
-       .name           = "auxclk1_ck",
+static const struct clksel auxclk0_sel[] = {
+       { .parent = &auxclk0_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk0_ck = {
+       .name           = "auxclk0_ck",
+       .parent         = &auxclk0_src_ck,
+       .clksel         = auxclk0_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK0,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
+static struct clk auxclk1_src_ck = {
+       .name           = "auxclk1_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK1,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2841,12 +2878,29 @@ static struct clk auxclk1_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
-static struct clk auxclk2_ck = {
-       .name           = "auxclk2_ck",
+static const struct clksel auxclk1_sel[] = {
+       { .parent = &auxclk1_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk1_ck = {
+       .name           = "auxclk1_ck",
+       .parent         = &auxclk1_src_ck,
+       .clksel         = auxclk1_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK1,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
+static struct clk auxclk2_src_ck = {
+       .name           = "auxclk2_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK2,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2854,12 +2908,29 @@ static struct clk auxclk2_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
-static struct clk auxclk3_ck = {
-       .name           = "auxclk3_ck",
+static const struct clksel auxclk2_sel[] = {
+       { .parent = &auxclk2_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk2_ck = {
+       .name           = "auxclk2_ck",
+       .parent         = &auxclk2_src_ck,
+       .clksel         = auxclk2_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK2,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
+static struct clk auxclk3_src_ck = {
+       .name           = "auxclk3_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK3,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2867,12 +2938,29 @@ static struct clk auxclk3_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
-static struct clk auxclk4_ck = {
-       .name           = "auxclk4_ck",
+static const struct clksel auxclk3_sel[] = {
+       { .parent = &auxclk3_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk3_ck = {
+       .name           = "auxclk3_ck",
+       .parent         = &auxclk3_src_ck,
+       .clksel         = auxclk3_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK3,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
+static struct clk auxclk4_src_ck = {
+       .name           = "auxclk4_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK4,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2880,12 +2968,29 @@ static struct clk auxclk4_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
-static struct clk auxclk5_ck = {
-       .name           = "auxclk5_ck",
+static const struct clksel auxclk4_sel[] = {
+       { .parent = &auxclk4_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk4_ck = {
+       .name           = "auxclk4_ck",
+       .parent         = &auxclk4_src_ck,
+       .clksel         = auxclk4_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK4,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
+static struct clk auxclk5_src_ck = {
+       .name           = "auxclk5_src_ck",
        .parent         = &sys_clkin_ck,
        .init           = &omap2_init_clksel_parent,
        .ops            = &clkops_omap2_dflt,
-       .clksel         = auxclk_sel,
+       .clksel         = auxclk_src_sel,
        .clksel_reg     = OMAP4_SCRM_AUXCLK5,
        .clksel_mask    = OMAP4_SRCSELECT_MASK,
        .recalc         = &omap2_clksel_recalc,
@@ -2893,6 +2998,23 @@ static struct clk auxclk5_ck = {
        .enable_bit     = OMAP4_ENABLE_SHIFT,
 };
 
+static const struct clksel auxclk5_sel[] = {
+       { .parent = &auxclk5_src_ck, .rates = div16_1to16_rates },
+       { .parent = NULL },
+};
+
+static struct clk auxclk5_ck = {
+       .name           = "auxclk5_ck",
+       .parent         = &auxclk5_src_ck,
+       .clksel         = auxclk5_sel,
+       .clksel_reg     = OMAP4_SCRM_AUXCLK5,
+       .clksel_mask    = OMAP4_CLKDIV_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+};
+
 static const struct clksel auxclkreq_sel[] = {
        { .parent = &auxclk0_ck, .rates = div_1_0_rates },
        { .parent = &auxclk1_ck, .rates = div_1_1_rates },
@@ -3093,12 +3215,12 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "gpio6_ick",                    &gpio6_ick,     CK_443X),
        CLK(NULL,       "gpmc_ick",                     &gpmc_ick,      CK_443X),
        CLK(NULL,       "gpu_fck",                      &gpu_fck,       CK_443X),
-       CLK("omap2_hdq.0",      "fck",                          &hdq1w_fck,     CK_443X),
+       CLK(NULL,       "hdq1w_fck",                    &hdq1w_fck,     CK_443X),
        CLK(NULL,       "hsi_fck",                      &hsi_fck,       CK_443X),
-       CLK("omap_i2c.1",       "fck",                          &i2c1_fck,      CK_443X),
-       CLK("omap_i2c.2",       "fck",                          &i2c2_fck,      CK_443X),
-       CLK("omap_i2c.3",       "fck",                          &i2c3_fck,      CK_443X),
-       CLK("omap_i2c.4",       "fck",                          &i2c4_fck,      CK_443X),
+       CLK(NULL,       "i2c1_fck",                     &i2c1_fck,      CK_443X),
+       CLK(NULL,       "i2c2_fck",                     &i2c2_fck,      CK_443X),
+       CLK(NULL,       "i2c3_fck",                     &i2c3_fck,      CK_443X),
+       CLK(NULL,       "i2c4_fck",                     &i2c4_fck,      CK_443X),
        CLK(NULL,       "ipu_fck",                      &ipu_fck,       CK_443X),
        CLK(NULL,       "iss_ctrlclk",                  &iss_ctrlclk,   CK_443X),
        CLK(NULL,       "iss_fck",                      &iss_fck,       CK_443X),
@@ -3109,23 +3231,23 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "mcasp_sync_mux_ck",            &mcasp_sync_mux_ck,     CK_443X),
        CLK(NULL,       "mcasp_fck",                    &mcasp_fck,     CK_443X),
        CLK(NULL,       "mcbsp1_sync_mux_ck",           &mcbsp1_sync_mux_ck,    CK_443X),
-       CLK("omap-mcbsp.1",     "fck",                          &mcbsp1_fck,    CK_443X),
+       CLK(NULL,       "mcbsp1_fck",                   &mcbsp1_fck,    CK_443X),
        CLK(NULL,       "mcbsp2_sync_mux_ck",           &mcbsp2_sync_mux_ck,    CK_443X),
-       CLK("omap-mcbsp.2",     "fck",                          &mcbsp2_fck,    CK_443X),
+       CLK(NULL,       "mcbsp2_fck",                   &mcbsp2_fck,    CK_443X),
        CLK(NULL,       "mcbsp3_sync_mux_ck",           &mcbsp3_sync_mux_ck,    CK_443X),
-       CLK("omap-mcbsp.3",     "fck",                          &mcbsp3_fck,    CK_443X),
+       CLK(NULL,       "mcbsp3_fck",                   &mcbsp3_fck,    CK_443X),
        CLK(NULL,       "mcbsp4_sync_mux_ck",           &mcbsp4_sync_mux_ck,    CK_443X),
-       CLK("omap-mcbsp.4",     "fck",                          &mcbsp4_fck,    CK_443X),
+       CLK(NULL,       "mcbsp4_fck",                   &mcbsp4_fck,    CK_443X),
        CLK(NULL,       "mcpdm_fck",                    &mcpdm_fck,     CK_443X),
-       CLK("omap2_mcspi.1",    "fck",                          &mcspi1_fck,    CK_443X),
-       CLK("omap2_mcspi.2",    "fck",                          &mcspi2_fck,    CK_443X),
-       CLK("omap2_mcspi.3",    "fck",                          &mcspi3_fck,    CK_443X),
-       CLK("omap2_mcspi.4",    "fck",                          &mcspi4_fck,    CK_443X),
-       CLK("omap_hsmmc.0",     "fck",                          &mmc1_fck,      CK_443X),
-       CLK("omap_hsmmc.1",     "fck",                          &mmc2_fck,      CK_443X),
-       CLK("omap_hsmmc.2",     "fck",                          &mmc3_fck,      CK_443X),
-       CLK("omap_hsmmc.3",     "fck",                          &mmc4_fck,      CK_443X),
-       CLK("omap_hsmmc.4",     "fck",                          &mmc5_fck,      CK_443X),
+       CLK(NULL,       "mcspi1_fck",                   &mcspi1_fck,    CK_443X),
+       CLK(NULL,       "mcspi2_fck",                   &mcspi2_fck,    CK_443X),
+       CLK(NULL,       "mcspi3_fck",                   &mcspi3_fck,    CK_443X),
+       CLK(NULL,       "mcspi4_fck",                   &mcspi4_fck,    CK_443X),
+       CLK(NULL,       "mmc1_fck",                     &mmc1_fck,      CK_443X),
+       CLK(NULL,       "mmc2_fck",                     &mmc2_fck,      CK_443X),
+       CLK(NULL,       "mmc3_fck",                     &mmc3_fck,      CK_443X),
+       CLK(NULL,       "mmc4_fck",                     &mmc4_fck,      CK_443X),
+       CLK(NULL,       "mmc5_fck",                     &mmc5_fck,      CK_443X),
        CLK(NULL,       "ocp2scp_usb_phy_phy_48m",      &ocp2scp_usb_phy_phy_48m,       CK_443X),
        CLK(NULL,       "ocp2scp_usb_phy_ick",          &ocp2scp_usb_phy_ick,   CK_443X),
        CLK(NULL,       "ocp_wp_noc_ick",               &ocp_wp_noc_ick,        CK_443X),
@@ -3182,21 +3304,27 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "usim_ck",                      &usim_ck,       CK_443X),
        CLK(NULL,       "usim_fclk",                    &usim_fclk,     CK_443X),
        CLK(NULL,       "usim_fck",                     &usim_fck,      CK_443X),
-       CLK("omap_wdt", "fck",                          &wd_timer2_fck, CK_443X),
+       CLK(NULL,       "wd_timer2_fck",                &wd_timer2_fck, CK_443X),
        CLK(NULL,       "wd_timer3_fck",                &wd_timer3_fck, CK_443X),
        CLK(NULL,       "stm_clk_div_ck",               &stm_clk_div_ck,        CK_443X),
        CLK(NULL,       "trace_clk_div_ck",             &trace_clk_div_ck,      CK_443X),
+       CLK(NULL,       "auxclk0_src_ck",               &auxclk0_src_ck,        CK_443X),
        CLK(NULL,       "auxclk0_ck",                   &auxclk0_ck,    CK_443X),
-       CLK(NULL,       "auxclk1_ck",                   &auxclk1_ck,    CK_443X),
-       CLK(NULL,       "auxclk2_ck",                   &auxclk2_ck,    CK_443X),
-       CLK(NULL,       "auxclk3_ck",                   &auxclk3_ck,    CK_443X),
-       CLK(NULL,       "auxclk4_ck",                   &auxclk4_ck,    CK_443X),
-       CLK(NULL,       "auxclk5_ck",                   &auxclk5_ck,    CK_443X),
        CLK(NULL,       "auxclkreq0_ck",                &auxclkreq0_ck, CK_443X),
+       CLK(NULL,       "auxclk1_src_ck",               &auxclk1_src_ck,        CK_443X),
+       CLK(NULL,       "auxclk1_ck",                   &auxclk1_ck,    CK_443X),
        CLK(NULL,       "auxclkreq1_ck",                &auxclkreq1_ck, CK_443X),
+       CLK(NULL,       "auxclk2_src_ck",               &auxclk2_src_ck,        CK_443X),
+       CLK(NULL,       "auxclk2_ck",                   &auxclk2_ck,    CK_443X),
        CLK(NULL,       "auxclkreq2_ck",                &auxclkreq2_ck, CK_443X),
+       CLK(NULL,       "auxclk3_src_ck",               &auxclk3_src_ck,        CK_443X),
+       CLK(NULL,       "auxclk3_ck",                   &auxclk3_ck,    CK_443X),
        CLK(NULL,       "auxclkreq3_ck",                &auxclkreq3_ck, CK_443X),
+       CLK(NULL,       "auxclk4_src_ck",               &auxclk4_src_ck,        CK_443X),
+       CLK(NULL,       "auxclk4_ck",                   &auxclk4_ck,    CK_443X),
        CLK(NULL,       "auxclkreq4_ck",                &auxclkreq4_ck, CK_443X),
+       CLK(NULL,       "auxclk5_src_ck",               &auxclk5_src_ck,        CK_443X),
+       CLK(NULL,       "auxclk5_ck",                   &auxclk5_ck,    CK_443X),
        CLK(NULL,       "auxclkreq5_ck",                &auxclkreq5_ck, CK_443X),
        CLK(NULL,       "gpmc_ck",                      &dummy_ck,      CK_443X),
        CLK(NULL,       "gpt1_ick",                     &dummy_ck,      CK_443X),
@@ -3251,6 +3379,7 @@ int __init omap4xxx_clk_init(void)
        }
 
        clk_init(&omap2_clk_functions);
+       omap2_clk_disable_clkdm_control();
 
        for (c = omap44xx_clks; c < omap44xx_clks + ARRAY_SIZE(omap44xx_clks);
                                                                          c++)
index 6cb6c03293df98030ed356c958ba501a90f76fbc..ab7db083f97fda3ffa9b6b5b419ae321878bc6ed 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * OMAP2/3/4 clockdomain framework functions
  *
- * Copyright (C) 2008-2010 Texas Instruments, Inc.
- * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2008-2011 Texas Instruments, Inc.
+ * Copyright (C) 2008-2011 Nokia Corporation
  *
  * Written by Paul Walmsley and Jouni Högander
  * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
@@ -92,6 +92,8 @@ static int _clkdm_register(struct clockdomain *clkdm)
 
        pwrdm_add_clkdm(pwrdm, clkdm);
 
+       spin_lock_init(&clkdm->lock);
+
        pr_debug("clockdomain: registered %s\n", clkdm->name);
 
        return 0;
@@ -690,6 +692,9 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
  */
 int clkdm_sleep(struct clockdomain *clkdm)
 {
+       int ret;
+       unsigned long flags;
+
        if (!clkdm)
                return -EINVAL;
 
@@ -704,7 +709,11 @@ int clkdm_sleep(struct clockdomain *clkdm)
 
        pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
 
-       return arch_clkdm->clkdm_sleep(clkdm);
+       spin_lock_irqsave(&clkdm->lock, flags);
+       clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
+       ret = arch_clkdm->clkdm_sleep(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
+       return ret;
 }
 
 /**
@@ -718,6 +727,9 @@ int clkdm_sleep(struct clockdomain *clkdm)
  */
 int clkdm_wakeup(struct clockdomain *clkdm)
 {
+       int ret;
+       unsigned long flags;
+
        if (!clkdm)
                return -EINVAL;
 
@@ -732,7 +744,11 @@ int clkdm_wakeup(struct clockdomain *clkdm)
 
        pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
 
-       return arch_clkdm->clkdm_wakeup(clkdm);
+       spin_lock_irqsave(&clkdm->lock, flags);
+       clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
+       ret = arch_clkdm->clkdm_wakeup(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
+       return ret;
 }
 
 /**
@@ -747,6 +763,8 @@ int clkdm_wakeup(struct clockdomain *clkdm)
  */
 void clkdm_allow_idle(struct clockdomain *clkdm)
 {
+       unsigned long flags;
+
        if (!clkdm)
                return;
 
@@ -762,8 +780,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
        pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
                 clkdm->name);
 
+       spin_lock_irqsave(&clkdm->lock, flags);
+       clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
        arch_clkdm->clkdm_allow_idle(clkdm);
        pwrdm_clkdm_state_switch(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
 }
 
 /**
@@ -777,6 +798,8 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
  */
 void clkdm_deny_idle(struct clockdomain *clkdm)
 {
+       unsigned long flags;
+
        if (!clkdm)
                return;
 
@@ -792,11 +815,90 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
        pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
                 clkdm->name);
 
+       spin_lock_irqsave(&clkdm->lock, flags);
+       clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
        arch_clkdm->clkdm_deny_idle(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
+}
+
+/**
+ * clkdm_in_hwsup - is clockdomain @clkdm have hardware-supervised idle enabled?
+ * @clkdm: struct clockdomain *
+ *
+ * Returns true if clockdomain @clkdm currently has
+ * hardware-supervised idle enabled, or false if it does not or if
+ * @clkdm is NULL.  It is only valid to call this function after
+ * clkdm_init() has been called.  This function does not actually read
+ * bits from the hardware; it instead tests an in-memory flag that is
+ * changed whenever the clockdomain code changes the auto-idle mode.
+ */
+bool clkdm_in_hwsup(struct clockdomain *clkdm)
+{
+       bool ret;
+       unsigned long flags;
+
+       if (!clkdm)
+               return false;
+
+       spin_lock_irqsave(&clkdm->lock, flags);
+       ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
+       spin_unlock_irqrestore(&clkdm->lock, flags);
+
+       return ret;
+}
+
+/* Clockdomain-to-clock/hwmod framework interface code */
+
+static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
+{
+       unsigned long flags;
+
+       if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
+               return -EINVAL;
+
+       /*
+        * For arch's with no autodeps, clkcm_clk_enable
+        * should be called for every clock instance or hwmod that is
+        * enabled, so the clkdm can be force woken up.
+        */
+       if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps)
+               return 0;
+
+       spin_lock_irqsave(&clkdm->lock, flags);
+       arch_clkdm->clkdm_clk_enable(clkdm);
+       pwrdm_wait_transition(clkdm->pwrdm.ptr);
+       pwrdm_clkdm_state_switch(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
+
+       pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
+
+       return 0;
 }
 
+static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
+{
+       unsigned long flags;
+
+       if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
+               return -EINVAL;
+
+       if (atomic_read(&clkdm->usecount) == 0) {
+               WARN_ON(1); /* underflow */
+               return -ERANGE;
+       }
+
+       if (atomic_dec_return(&clkdm->usecount) > 0)
+               return 0;
+
+       spin_lock_irqsave(&clkdm->lock, flags);
+       arch_clkdm->clkdm_clk_disable(clkdm);
+       pwrdm_clkdm_state_switch(clkdm);
+       spin_unlock_irqrestore(&clkdm->lock, flags);
 
-/* Clockdomain-to-clock framework interface code */
+       pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
+
+       return 0;
+}
 
 /**
  * clkdm_clk_enable - add an enabled downstream clock to this clkdm
@@ -819,25 +921,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
         * downstream clocks for debugging purposes?
         */
 
-       if (!clkdm || !clk)
+       if (!clk)
                return -EINVAL;
 
-       if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable)
-               return -EINVAL;
-
-       if (atomic_inc_return(&clkdm->usecount) > 1)
-               return 0;
-
-       /* Clockdomain now has one enabled downstream clock */
-
-       pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
-                clk->name);
-
-       arch_clkdm->clkdm_clk_enable(clkdm);
-       pwrdm_wait_transition(clkdm->pwrdm.ptr);
-       pwrdm_clkdm_state_switch(clkdm);
-
-       return 0;
+       return _clkdm_clk_hwmod_enable(clkdm);
 }
 
 /**
@@ -850,9 +937,8 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
  * clockdomain usecount goes to 0, put the clockdomain to sleep
  * (software-supervised mode) or remove the clkdm autodependencies
  * (hardware-supervised mode).  Returns -EINVAL if passed null
- * pointers; -ERANGE if the @clkdm usecount underflows and debugging
- * is enabled; or returns 0 upon success or if the clockdomain is in
- * hwsup idle mode.
+ * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0
+ * upon success or if the clockdomain is in hwsup idle mode.
  */
 int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
 {
@@ -861,30 +947,72 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
         * downstream clocks for debugging purposes?
         */
 
-       if (!clkdm || !clk)
+       if (!clk)
                return -EINVAL;
 
-       if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable)
+       return _clkdm_clk_hwmod_disable(clkdm);
+}
+
+/**
+ * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm
+ * @clkdm: struct clockdomain *
+ * @oh: struct omap_hwmod * of the enabled downstream hwmod
+ *
+ * Increment the usecount of the clockdomain @clkdm and ensure that it
+ * is awake before @oh is enabled. Intended to be called by
+ * module_enable() code.
+ * If the clockdomain is in software-supervised idle mode, force the
+ * clockdomain to wake.  If the clockdomain is in hardware-supervised idle
+ * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the
+ * clockdomain can be read from/written to by on-chip processors.
+ * Returns -EINVAL if passed null pointers;
+ * returns 0 upon success or if the clockdomain is in hwsup idle mode.
+ */
+int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
+{
+       /* The clkdm attribute does not exist yet prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return 0;
+
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream hwmods for debugging purposes?
+        */
+
+       if (!oh)
                return -EINVAL;
 
-#ifdef DEBUG
-       if (atomic_read(&clkdm->usecount) == 0) {
-               WARN_ON(1); /* underflow */
-               return -ERANGE;
-       }
-#endif
+       return _clkdm_clk_hwmod_enable(clkdm);
+}
 
-       if (atomic_dec_return(&clkdm->usecount) > 0)
+/**
+ * clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm
+ * @clkdm: struct clockdomain *
+ * @oh: struct omap_hwmod * of the disabled downstream hwmod
+ *
+ * Decrement the usecount of this clockdomain @clkdm when @oh is
+ * disabled. Intended to be called by module_disable() code.
+ * If the clockdomain usecount goes to 0, put the clockdomain to sleep
+ * (software-supervised mode) or remove the clkdm autodependencies
+ * (hardware-supervised mode).
+ * Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount
+ * underflows; or returns 0 upon success or if the clockdomain is in hwsup
+ * idle mode.
+ */
+int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
+{
+       /* The clkdm attribute does not exist yet prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
                return 0;
 
-       /* All downstream clocks of this clockdomain are now disabled */
-
-       pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
-                clk->name);
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream hwmods for debugging purposes?
+        */
 
-       arch_clkdm->clkdm_clk_disable(clkdm);
-       pwrdm_clkdm_state_switch(clkdm);
+       if (!oh)
+               return -EINVAL;
 
-       return 0;
+       return _clkdm_clk_hwmod_disable(clkdm);
 }
 
index 5823584d9cd75086b53f20f33f60ece273c8e906..1e50c88b8a07022c4697434ca7f024dc24b546a7 100644 (file)
 #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
 
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include "powerdomain.h"
 #include <plat/clock.h>
+#include <plat/omap_hwmod.h>
 #include <plat/cpu.h>
 
 /*
@@ -82,6 +84,9 @@ struct clkdm_dep {
        const struct omap_chip_id omap_chip;
 };
 
+/* Possible flags for struct clockdomain._flags */
+#define _CLKDM_FLAG_HWSUP_ENABLED              BIT(0)
+
 /**
  * struct clockdomain - OMAP clockdomain
  * @name: clockdomain name
@@ -89,6 +94,7 @@ struct clkdm_dep {
  * @clktrctrl_reg: CLKSTCTRL reg for the given clock domain
  * @clktrctrl_mask: CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg
  * @flags: Clockdomain capability flags
+ * @_flags: Flags for use only by internal clockdomain code
  * @dep_bit: Bit shift of this clockdomain's PM_WKDEP/CM_SLEEPDEP bit
  * @prcm_partition: (OMAP4 only) PRCM partition ID for this clkdm's registers
  * @cm_inst: (OMAP4 only) CM instance register offset
@@ -113,6 +119,7 @@ struct clockdomain {
        } pwrdm;
        const u16 clktrctrl_mask;
        const u8 flags;
+       u8 _flags;
        const u8 dep_bit;
        const u8 prcm_partition;
        const s16 cm_inst;
@@ -122,6 +129,7 @@ struct clockdomain {
        const struct omap_chip_id omap_chip;
        atomic_t usecount;
        struct list_head node;
+       spinlock_t lock;
 };
 
 /**
@@ -177,12 +185,15 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
 
 void clkdm_allow_idle(struct clockdomain *clkdm);
 void clkdm_deny_idle(struct clockdomain *clkdm);
+bool clkdm_in_hwsup(struct clockdomain *clkdm);
 
 int clkdm_wakeup(struct clockdomain *clkdm);
 int clkdm_sleep(struct clockdomain *clkdm);
 
 int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
 int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
+int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh);
+int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh);
 
 extern void __init omap2xxx_clockdomains_init(void);
 extern void __init omap3xxx_clockdomains_init(void);
index 48d0db7e6069c90eff01a245153dba465b562b27..f740edb111f4e0f62fbe12cdce9f246f138229d2 100644 (file)
@@ -183,7 +183,8 @@ static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
                _clkdm_add_autodeps(clkdm);
                _enable_hwsup(clkdm);
        } else {
-               clkdm_wakeup(clkdm);
+               if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+                       omap2_clkdm_wakeup(clkdm);
        }
 
        return 0;
@@ -205,7 +206,8 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
                _clkdm_del_autodeps(clkdm);
                _enable_hwsup(clkdm);
        } else {
-               clkdm_sleep(clkdm);
+               if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
+                       omap2_clkdm_sleep(clkdm);
        }
 
        return 0;
index a1a4ecd26544004d8d13f013c419e244f7415f79..b43706aa08bd89bccbce5c715f127212cafa0964 100644 (file)
@@ -95,13 +95,8 @@ static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
 
 static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
 {
-       bool hwsup = false;
-
-       hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
-                                       clkdm->cm_inst, clkdm->clkdm_offs);
-
-       if (!hwsup)
-               clkdm_wakeup(clkdm);
+       if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+               return omap4_clkdm_wakeup(clkdm);
 
        return 0;
 }
@@ -113,8 +108,8 @@ static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
        hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
                                        clkdm->cm_inst, clkdm->clkdm_offs);
 
-       if (!hwsup)
-               clkdm_sleep(clkdm);
+       if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
+               omap4_clkdm_sleep(clkdm);
 
        return 0;
 }
index 66090f2676ceb85894bb9c6f071d4a116769819a..dccc651fa0d0ebedefb5d998bdefdfffcba32d7a 100644 (file)
@@ -565,7 +565,7 @@ static struct clockdomain ducati_44xx_clkdm = {
 };
 
 static struct clockdomain mpu_44xx_clkdm = {
-       .name             = "mpu_clkdm",
+       .name             = "mpuss_clkdm",
        .pwrdm            = { .name = "mpu_pwrdm" },
        .prcm_partition   = OMAP4430_CM1_PARTITION,
        .cm_inst          = OMAP4430_CM1_MPU_INST,
index 0b87ec82b41c89c103d453b846fa54370a086da0..3380beeace6e2173db2e06017bceb1457999eaf4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * OMAP4 Clock Management (CM) definitions
  *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ * Copyright (C) 2007-2011 Texas Instruments, Inc.
  * Copyright (C) 2007-2009 Nokia Corporation
  *
  * Written by Paul Walmsley
 #define OMAP4_CM_CLKSTCTRL                             0x0000
 #define OMAP4_CM_STATICDEP                             0x0004
 
-/* Function prototypes */
-# ifndef __ASSEMBLER__
-
-extern int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg);
-
-# endif
 #endif
index a482bfa0a9541bb046342f5bda79b4c2c5f604a9..eb2a472bbf466416fceee1962152bab518242fa6 100644 (file)
@@ -2,6 +2,7 @@
  * OMAP4 CM instance functions
  *
  * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
 #include "prm44xx.h"
 #include "prcm_mpu44xx.h"
 
+/*
+ * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
+ *
+ *   0x0 func:     Module is fully functional, including OCP
+ *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
+ *                 abortion
+ *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
+ *                 using separate functional clock
+ *   0x3 disabled: Module is disabled and cannot be accessed
+ *
+ */
+#define CLKCTRL_IDLEST_FUNCTIONAL              0x0
+#define CLKCTRL_IDLEST_INTRANSITION            0x1
+#define CLKCTRL_IDLEST_INTERFACE_IDLE          0x2
+#define CLKCTRL_IDLEST_DISABLED                        0x3
+
 static u32 _cm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
        [OMAP4430_INVALID_PRCM_PARTITION]       = 0,
        [OMAP4430_PRM_PARTITION]                = OMAP4430_PRM_BASE,
@@ -41,6 +58,48 @@ static u32 _cm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
        [OMAP4430_PRCM_MPU_PARTITION]           = OMAP4430_PRCM_MPU_BASE,
 };
 
+/* Private functions */
+
+/**
+ * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ *
+ * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
+ * bit 0.
+ */
+static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+{
+       u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
+       v &= OMAP4430_IDLEST_MASK;
+       v >>= OMAP4430_IDLEST_SHIFT;
+       return v;
+}
+
+/**
+ * _is_module_ready - can module registers be accessed without causing an abort?
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ *
+ * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
+ * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
+ */
+static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+{
+       u32 v;
+
+       v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs);
+
+       return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
+               v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
+}
+
+/* Public functions */
+
 /* Read a register in a CM instance */
 u32 omap4_cminst_read_inst_reg(u8 part, s16 inst, u16 idx)
 {
@@ -200,36 +259,93 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs)
  */
 
 /**
- * omap4_cm_wait_module_ready - wait for a module to be in 'func' state
- * @clkctrl_reg: CLKCTRL module address
+ * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  *
  * Wait for the module IDLEST to be functional. If the idle state is in any
  * the non functional state (trans, idle or disabled), module and thus the
  * sysconfig cannot be accessed and will probably lead to an "imprecise
  * external abort"
+ */
+int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
+                                  u16 clkctrl_offs)
+{
+       int i = 0;
+
+       if (!clkctrl_offs)
+               return 0;
+
+       omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs),
+                         MAX_MODULE_READY_TIME, i);
+
+       return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
+}
+
+/**
+ * omap4_cminst_wait_module_idle - wait for a module to be in 'disabled'
+ * state
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  *
- * Module idle state:
- *   0x0 func:     Module is fully functional, including OCP
- *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
- *                 abortion
- *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
- *                 using separate functional clock
- *   0x3 disabled: Module is disabled and cannot be accessed
- *
+ * Wait for the module IDLEST to be disabled. Some PRCM transition,
+ * like reset assertion or parent clock de-activation must wait the
+ * module to be fully disabled.
  */
-int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
+int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
 {
        int i = 0;
 
-       if (!clkctrl_reg)
+       if (!clkctrl_offs)
                return 0;
 
-       omap_test_timeout((
-               ((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) == 0) ||
-                (((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) >>
-                 OMAP4430_IDLEST_SHIFT) == 0x2)),
-               MAX_MODULE_READY_TIME, i);
+       omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) ==
+                          CLKCTRL_IDLEST_DISABLED),
+                         MAX_MODULE_READY_TIME, i);
 
        return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 }
 
+/**
+ * omap4_cminst_module_enable - Enable the modulemode inside CLKCTRL
+ * @mode: Module mode (SW or HW)
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ *
+ * No return value.
+ */
+void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
+                           u16 clkctrl_offs)
+{
+       u32 v;
+
+       v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
+       v &= ~OMAP4430_MODULEMODE_MASK;
+       v |= mode << OMAP4430_MODULEMODE_SHIFT;
+       omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
+}
+
+/**
+ * omap4_cminst_module_disable - Disable the module inside CLKCTRL
+ * @part: PRCM partition ID that the CM_CLKCTRL register exists in
+ * @inst: CM instance register offset (*_INST macro)
+ * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
+ * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ *
+ * No return value.
+ */
+void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
+                            u16 clkctrl_offs)
+{
+       u32 v;
+
+       v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
+       v &= ~OMAP4430_MODULEMODE_MASK;
+       omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
+}
index 2b32c181a2ee26175a22e86e347722eefab19cca..f2ea6453ade0b7ff1ee4119daf3d274648208fa4 100644 (file)
@@ -17,6 +17,14 @@ extern void omap4_cminst_clkdm_disable_hwsup(u8 part, s16 inst, u16 cdoffs);
 extern void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs);
 extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs);
 
+extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
+extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
+
+extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
+                                      u16 clkctrl_offs);
+extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
+                                       u16 clkctrl_offs);
+
 /*
  * In an ideal world, we would not export these low-level functions,
  * but this will probably take some time to fix properly
@@ -32,6 +40,4 @@ extern u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, s16 inst,
 extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx,
                                           u32 mask);
 
-extern int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg);
-
 #endif
index 02b6016393a8ff24cba4e11af5fbac8738068f82..84cc0bdda3aecd0d5065f7d3a0b471f3eb524383 100644 (file)
 #include <plat/prcm.h>
 
 #include "cm2xxx_3xxx.h"
-#include "cm44xx.h"
+#include "cminst44xx.h"
 #include "prm2xxx_3xxx.h"
 #include "prm44xx.h"
+#include "prminst44xx.h"
 #include "mux.h"
 
 /* Maximum microseconds to wait for OMAP module to softreset */
@@ -678,6 +679,56 @@ static void _disable_optional_clocks(struct omap_hwmod *oh)
                }
 }
 
+/**
+ * _enable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Enables the PRCM module mode related to the hwmod @oh.
+ * No return value.
+ */
+static void _enable_module(struct omap_hwmod *oh)
+{
+       /* The module mode does not exist prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return;
+
+       if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+               return;
+
+       pr_debug("omap_hwmod: %s: _enable_module: %d\n",
+                oh->name, oh->prcm.omap4.modulemode);
+
+       omap4_cminst_module_enable(oh->prcm.omap4.modulemode,
+                                  oh->clkdm->prcm_partition,
+                                  oh->clkdm->cm_inst,
+                                  oh->clkdm->clkdm_offs,
+                                  oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
+ * _disable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Disable the PRCM module mode related to the hwmod @oh.
+ * No return value.
+ */
+static void _disable_module(struct omap_hwmod *oh)
+{
+       /* The module mode does not exist prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return;
+
+       if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+               return;
+
+       pr_debug("omap_hwmod: %s: _disable_module\n", oh->name);
+
+       omap4_cminst_module_disable(oh->clkdm->prcm_partition,
+                                   oh->clkdm->cm_inst,
+                                   oh->clkdm->clkdm_offs,
+                                   oh->prcm.omap4.clkctrl_offs);
+}
+
 /**
  * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
  * @oh: struct omap_hwmod *oh
@@ -990,9 +1041,40 @@ static struct omap_hwmod *_lookup(const char *name)
 
        return oh;
 }
+/**
+ * _init_clkdm - look up a clockdomain name, store pointer in omap_hwmod
+ * @oh: struct omap_hwmod *
+ *
+ * Convert a clockdomain name stored in a struct omap_hwmod into a
+ * clockdomain pointer, and save it into the struct omap_hwmod.
+ * return -EINVAL if clkdm_name does not exist or if the lookup failed.
+ */
+static int _init_clkdm(struct omap_hwmod *oh)
+{
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return 0;
+
+       if (!oh->clkdm_name) {
+               pr_warning("omap_hwmod: %s: no clkdm_name\n", oh->name);
+               return -EINVAL;
+       }
+
+       oh->clkdm = clkdm_lookup(oh->clkdm_name);
+       if (!oh->clkdm) {
+               pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n",
+                       oh->name, oh->clkdm_name);
+               return -EINVAL;
+       }
+
+       pr_debug("omap_hwmod: %s: associated to clkdm %s\n",
+               oh->name, oh->clkdm_name);
+
+       return 0;
+}
 
 /**
- * _init_clocks - clk_get() all clocks associated with this hwmod
+ * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as
+ * well the clockdomain.
  * @oh: struct omap_hwmod *
  * @data: not used; pass NULL
  *
@@ -1012,6 +1094,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data)
        ret |= _init_main_clk(oh);
        ret |= _init_interface_clks(oh);
        ret |= _init_opt_clks(oh);
+       ret |= _init_clkdm(oh);
 
        if (!ret)
                oh->_state = _HWMOD_STATE_CLKS_INITED;
@@ -1028,7 +1111,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data)
  * Wait for a module @oh to leave slave idle.  Returns 0 if the module
  * does not have an IDLEST bit or if the module successfully leaves
  * slave idle; otherwise, pass along the return value of the
- * appropriate *_cm_wait_module_ready() function.
+ * appropriate *_cm*_wait_module_ready() function.
  */
 static int _wait_target_ready(struct omap_hwmod *oh)
 {
@@ -1055,7 +1138,13 @@ static int _wait_target_ready(struct omap_hwmod *oh)
                                                 oh->prcm.omap2.idlest_reg_id,
                                                 oh->prcm.omap2.idlest_idle_bit);
        } else if (cpu_is_omap44xx()) {
-               ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg);
+               if (!oh->clkdm)
+                       return -EINVAL;
+
+               ret = omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition,
+                                                    oh->clkdm->cm_inst,
+                                                    oh->clkdm->clkdm_offs,
+                                                    oh->prcm.omap4.clkctrl_offs);
        } else {
                BUG();
        };
@@ -1063,6 +1152,36 @@ static int _wait_target_ready(struct omap_hwmod *oh)
        return ret;
 }
 
+/**
+ * _wait_target_disable - wait for a module to be disabled
+ * @oh: struct omap_hwmod *
+ *
+ * Wait for a module @oh to enter slave idle.  Returns 0 if the module
+ * does not have an IDLEST bit or if the module successfully enters
+ * slave idle; otherwise, pass along the return value of the
+ * appropriate *_cm*_wait_module_idle() function.
+ */
+static int _wait_target_disable(struct omap_hwmod *oh)
+{
+       /* TODO: For now just handle OMAP4+ */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return 0;
+
+       if (!oh)
+               return -EINVAL;
+
+       if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+               return 0;
+
+       if (oh->flags & HWMOD_NO_IDLEST)
+               return 0;
+
+       return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition,
+                                            oh->clkdm->cm_inst,
+                                            oh->clkdm->clkdm_offs,
+                                            oh->prcm.omap4.clkctrl_offs);
+}
+
 /**
  * _lookup_hardreset - fill register bit info for this hwmod/reset line
  * @oh: struct omap_hwmod *
@@ -1119,8 +1238,10 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
                return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
                                                  ohri.rst_shift);
        else if (cpu_is_omap44xx())
-               return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
-                                                 ohri.rst_shift);
+               return omap4_prminst_assert_hardreset(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        else
                return -EINVAL;
 }
@@ -1155,8 +1276,10 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
                if (ohri.st_shift)
                        pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
                               oh->name, name);
-               ret = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
-                                                  ohri.rst_shift);
+               ret = omap4_prminst_deassert_hardreset(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        } else {
                return -EINVAL;
        }
@@ -1191,8 +1314,10 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
                return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
                                                       ohri.st_shift);
        } else if (cpu_is_omap44xx()) {
-               return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
-                                                      ohri.rst_shift);
+               return omap4_prminst_is_hardreset_asserted(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        } else {
                return -EINVAL;
        }
@@ -1312,6 +1437,7 @@ static int _reset(struct omap_hwmod *oh)
 static int _enable(struct omap_hwmod *oh)
 {
        int r;
+       int hwsup = 0;
 
        pr_debug("omap_hwmod: %s: enabling\n", oh->name);
 
@@ -1323,14 +1449,6 @@ static int _enable(struct omap_hwmod *oh)
                return -EINVAL;
        }
 
-       /* Mux pins for device runtime if populated */
-       if (oh->mux && (!oh->mux->enabled ||
-                       ((oh->_state == _HWMOD_STATE_IDLE) &&
-                        oh->mux->pads_dynamic)))
-               omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
-
-       _add_initiator_dep(oh, mpu_oh);
-       _enable_clocks(oh);
 
        /*
         * If an IP contains only one HW reset line, then de-assert it in order
@@ -1341,22 +1459,56 @@ static int _enable(struct omap_hwmod *oh)
             oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
                _deassert_hardreset(oh, oh->rst_lines[0].name);
 
-       r = _wait_target_ready(oh);
-       if (r) {
-               pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
-                        oh->name, r);
-               _disable_clocks(oh);
+       /* Mux pins for device runtime if populated */
+       if (oh->mux && (!oh->mux->enabled ||
+                       ((oh->_state == _HWMOD_STATE_IDLE) &&
+                        oh->mux->pads_dynamic)))
+               omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
 
-               return r;
+       _add_initiator_dep(oh, mpu_oh);
+
+       if (oh->clkdm) {
+               /*
+                * A clockdomain must be in SW_SUP before enabling
+                * completely the module. The clockdomain can be set
+                * in HW_AUTO only when the module become ready.
+                */
+               hwsup = clkdm_in_hwsup(oh->clkdm);
+               r = clkdm_hwmod_enable(oh->clkdm, oh);
+               if (r) {
+                       WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
+                            oh->name, oh->clkdm->name, r);
+                       return r;
+               }
        }
 
-       oh->_state = _HWMOD_STATE_ENABLED;
+       _enable_clocks(oh);
+       _enable_module(oh);
 
-       /* Access the sysconfig only if the target is ready */
-       if (oh->class->sysc) {
-               if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
-                       _update_sysc_cache(oh);
-               _enable_sysc(oh);
+       r = _wait_target_ready(oh);
+       if (!r) {
+               /*
+                * Set the clockdomain to HW_AUTO only if the target is ready,
+                * assuming that the previous state was HW_AUTO
+                */
+               if (oh->clkdm && hwsup)
+                       clkdm_allow_idle(oh->clkdm);
+
+               oh->_state = _HWMOD_STATE_ENABLED;
+
+               /* Access the sysconfig only if the target is ready */
+               if (oh->class->sysc) {
+                       if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
+                               _update_sysc_cache(oh);
+                       _enable_sysc(oh);
+               }
+       } else {
+               _disable_clocks(oh);
+               pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
+                        oh->name, r);
+
+               if (oh->clkdm)
+                       clkdm_hwmod_disable(oh->clkdm, oh);
        }
 
        return r;
@@ -1372,6 +1524,8 @@ static int _enable(struct omap_hwmod *oh)
  */
 static int _idle(struct omap_hwmod *oh)
 {
+       int ret;
+
        pr_debug("omap_hwmod: %s: idling\n", oh->name);
 
        if (oh->_state != _HWMOD_STATE_ENABLED) {
@@ -1383,7 +1537,20 @@ static int _idle(struct omap_hwmod *oh)
        if (oh->class->sysc)
                _idle_sysc(oh);
        _del_initiator_dep(oh, mpu_oh);
+       _disable_module(oh);
+       ret = _wait_target_disable(oh);
+       if (ret)
+               pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+                       oh->name);
+       /*
+        * The module must be in idle mode before disabling any parents
+        * clocks. Otherwise, the parent clock might be disabled before
+        * the module transition is done, and thus will prevent the
+        * transition to complete properly.
+        */
        _disable_clocks(oh);
+       if (oh->clkdm)
+               clkdm_hwmod_disable(oh->clkdm, oh);
 
        /* Mux pins for device idle if populated */
        if (oh->mux && oh->mux->pads_dynamic)
@@ -1475,7 +1642,14 @@ static int _shutdown(struct omap_hwmod *oh)
        if (oh->_state == _HWMOD_STATE_ENABLED) {
                _del_initiator_dep(oh, mpu_oh);
                /* XXX what about the other system initiators here? dma, dsp */
+               _disable_module(oh);
+               ret = _wait_target_disable(oh);
+               if (ret)
+                       pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+                               oh->name);
                _disable_clocks(oh);
+               if (oh->clkdm)
+                       clkdm_hwmod_disable(oh->clkdm, oh);
        }
        /* XXX Should this code also force-disable the optional clocks? */
 
index 5d5df49749dfe5b69ceccdc71896ecdf4f837940..6201422c0606b5103c01e563f67060134658774d 100644 (file)
@@ -123,9 +123,16 @@ static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
 static struct omap_hwmod omap44xx_dmm_hwmod = {
        .name           = "dmm",
        .class          = &omap44xx_dmm_hwmod_class,
-       .mpu_irqs       = omap44xx_dmm_irqs,
+       .clkdm_name     = "l3_emif_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_MEMIF_DMM_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_dmm_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_dmm_slaves),
+       .mpu_irqs       = omap44xx_dmm_irqs,
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
 };
 
@@ -173,6 +180,13 @@ static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
 static struct omap_hwmod omap44xx_emif_fw_hwmod = {
        .name           = "emif_fw",
        .class          = &omap44xx_emif_fw_hwmod_class,
+       .clkdm_name     = "l3_emif_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_MEMIF_EMIF_FW_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_emif_fw_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_emif_fw_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -212,6 +226,14 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
 static struct omap_hwmod omap44xx_l3_instr_hwmod = {
        .name           = "l3_instr",
        .class          = &omap44xx_l3_hwmod_class,
+       .clkdm_name     = "l3_instr_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
        .slaves         = omap44xx_l3_instr_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_instr_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -304,7 +326,14 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
 static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
        .name           = "l3_main_1",
        .class          = &omap44xx_l3_hwmod_class,
+       .clkdm_name     = "l3_1_clkdm",
        .mpu_irqs       = omap44xx_l3_main_1_irqs,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l3_main_1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_1_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -400,6 +429,13 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
 static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
        .name           = "l3_main_2",
        .class          = &omap44xx_l3_hwmod_class,
+       .clkdm_name     = "l3_2_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3_2_L3_2_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l3_main_2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_2_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -450,6 +486,14 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
 static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
        .name           = "l3_main_3",
        .class          = &omap44xx_l3_hwmod_class,
+       .clkdm_name     = "l3_instr_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INSTR_L3_3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
        .slaves         = omap44xx_l3_main_3_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_3_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -507,6 +551,12 @@ static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
 static struct omap_hwmod omap44xx_l4_abe_hwmod = {
        .name           = "l4_abe",
        .class          = &omap44xx_l4_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l4_abe_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_abe_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -529,6 +579,13 @@ static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
 static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
        .name           = "l4_cfg",
        .class          = &omap44xx_l4_hwmod_class,
+       .clkdm_name     = "l4_cfg_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4CFG_L4_CFG_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l4_cfg_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_cfg_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -551,6 +608,13 @@ static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
 static struct omap_hwmod omap44xx_l4_per_hwmod = {
        .name           = "l4_per",
        .class          = &omap44xx_l4_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_L4_PER_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l4_per_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_per_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -573,6 +637,13 @@ static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
 static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
        .name           = "l4_wkup",
        .class          = &omap44xx_l4_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_WKUP_L4WKUP_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_L4WKUP_CONTEXT_OFFSET,
+               },
+       },
        .slaves         = omap44xx_l4_wkup_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_wkup_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -603,6 +674,7 @@ static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
 static struct omap_hwmod omap44xx_mpu_private_hwmod = {
        .name           = "mpu_private",
        .class          = &omap44xx_mpu_bus_hwmod_class,
+       .clkdm_name     = "mpuss_clkdm",
        .slaves         = omap44xx_mpu_private_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_mpu_private_slaves),
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -741,12 +813,15 @@ static struct omap_hwmod_ocp_if *omap44xx_aess_slaves[] = {
 static struct omap_hwmod omap44xx_aess_hwmod = {
        .name           = "aess",
        .class          = &omap44xx_aess_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_aess_irqs,
        .sdma_reqs      = omap44xx_aess_sdma_reqs,
        .main_clk       = "aess_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_AESS_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_aess_slaves,
@@ -773,9 +848,10 @@ static struct omap_hwmod_opt_clk bandgap_opt_clks[] = {
 static struct omap_hwmod omap44xx_bandgap_hwmod = {
        .name           = "bandgap",
        .class          = &omap44xx_bandgap_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
                },
        },
        .opt_clks       = bandgap_opt_clks,
@@ -830,11 +906,13 @@ static struct omap_hwmod_ocp_if *omap44xx_counter_32k_slaves[] = {
 static struct omap_hwmod omap44xx_counter_32k_hwmod = {
        .name           = "counter_32k",
        .class          = &omap44xx_counter_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .flags          = HWMOD_SWSUP_SIDLE,
        .main_clk       = "sys_32k_ck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_SYNCTIMER_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_SYNCTIMER_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_SYNCTIMER_CONTEXT_OFFSET,
                },
        },
        .slaves         = omap44xx_counter_32k_slaves,
@@ -913,11 +991,13 @@ static struct omap_hwmod_ocp_if *omap44xx_dma_system_slaves[] = {
 static struct omap_hwmod omap44xx_dma_system_hwmod = {
        .name           = "dma_system",
        .class          = &omap44xx_dma_hwmod_class,
+       .clkdm_name     = "l3_dma_clkdm",
        .mpu_irqs       = omap44xx_dma_system_irqs,
        .main_clk       = "l3_div_ck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_SDMA_SDMA_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_SDMA_SDMA_CONTEXT_OFFSET,
                },
        },
        .dev_attr       = &dma_dev_attr,
@@ -1005,12 +1085,15 @@ static struct omap_hwmod_ocp_if *omap44xx_dmic_slaves[] = {
 static struct omap_hwmod omap44xx_dmic_hwmod = {
        .name           = "dmic",
        .class          = &omap44xx_dmic_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_dmic_irqs,
        .sdma_reqs      = omap44xx_dmic_sdma_reqs,
        .main_clk       = "dmic_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_DMIC_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_DMIC_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_dmic_slaves,
@@ -1072,12 +1155,13 @@ static struct omap_hwmod_ocp_if *omap44xx_dsp_slaves[] = {
 static struct omap_hwmod omap44xx_dsp_c0_hwmod = {
        .name           = "dsp_c0",
        .class          = &omap44xx_dsp_hwmod_class,
+       .clkdm_name     = "tesla_clkdm",
        .flags          = HWMOD_INIT_NO_RESET,
        .rst_lines      = omap44xx_dsp_c0_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_dsp_c0_resets),
        .prcm = {
                .omap4 = {
-                       .rstctrl_reg = OMAP4430_RM_TESLA_RSTCTRL,
+                       .rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
                },
        },
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -1086,14 +1170,17 @@ static struct omap_hwmod omap44xx_dsp_c0_hwmod = {
 static struct omap_hwmod omap44xx_dsp_hwmod = {
        .name           = "dsp",
        .class          = &omap44xx_dsp_hwmod_class,
+       .clkdm_name     = "tesla_clkdm",
        .mpu_irqs       = omap44xx_dsp_irqs,
        .rst_lines      = omap44xx_dsp_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_dsp_resets),
        .main_clk       = "dsp_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL,
-                       .rstctrl_reg = OMAP4430_RM_TESLA_RSTCTRL,
+                       .clkctrl_offs = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET,
+                       .rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_TESLA_TESLA_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .slaves         = omap44xx_dsp_slaves,
@@ -1177,10 +1264,12 @@ static struct omap_hwmod_opt_clk dss_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_hwmod = {
        .name           = "dss_core",
        .class          = &omap44xx_dss_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_opt_clks,
@@ -1278,13 +1367,14 @@ static struct omap_hwmod_opt_clk dss_dispc_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
        .name           = "dss_dispc",
        .class          = &omap44xx_dispc_hwmod_class,
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dispc_irqs,
        .sdma_reqs      = omap44xx_dss_dispc_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_dispc_opt_clks,
@@ -1376,12 +1466,14 @@ static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
        .name           = "dss_dsi1",
        .class          = &omap44xx_dsi_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dsi1_irqs,
        .sdma_reqs      = omap44xx_dss_dsi1_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_dsi1_opt_clks,
@@ -1452,12 +1544,14 @@ static struct omap_hwmod_opt_clk dss_dsi2_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
        .name           = "dss_dsi2",
        .class          = &omap44xx_dsi_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dsi2_irqs,
        .sdma_reqs      = omap44xx_dss_dsi2_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_dsi2_opt_clks,
@@ -1548,12 +1642,14 @@ static struct omap_hwmod_opt_clk dss_hdmi_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
        .name           = "dss_hdmi",
        .class          = &omap44xx_hdmi_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_hdmi_irqs,
        .sdma_reqs      = omap44xx_dss_hdmi_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_hdmi_opt_clks,
@@ -1639,11 +1735,13 @@ static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
 static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
        .name           = "dss_rfbi",
        .class          = &omap44xx_rfbi_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .sdma_reqs      = omap44xx_dss_rfbi_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .opt_clks       = dss_rfbi_opt_clks,
@@ -1709,10 +1807,12 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = {
 static struct omap_hwmod omap44xx_dss_venc_hwmod = {
        .name           = "dss_venc",
        .class          = &omap44xx_venc_hwmod_class,
+       .clkdm_name     = "l3_dss_clkdm",
        .main_clk       = "dss_dss_clk",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
                },
        },
        .slaves         = omap44xx_dss_venc_slaves,
@@ -1786,11 +1886,14 @@ static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio1_hwmod = {
        .name           = "gpio1",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .mpu_irqs       = omap44xx_gpio1_irqs,
        .main_clk       = "gpio1_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_GPIO1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio1_opt_clks,
@@ -1838,12 +1941,15 @@ static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio2_hwmod = {
        .name           = "gpio2",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap44xx_gpio2_irqs,
        .main_clk       = "gpio2_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_GPIO2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_GPIO2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio2_opt_clks,
@@ -1891,12 +1997,15 @@ static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio3_hwmod = {
        .name           = "gpio3",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap44xx_gpio3_irqs,
        .main_clk       = "gpio3_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_GPIO3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio3_opt_clks,
@@ -1944,12 +2053,15 @@ static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio4_hwmod = {
        .name           = "gpio4",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap44xx_gpio4_irqs,
        .main_clk       = "gpio4_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_GPIO4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_GPIO4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio4_opt_clks,
@@ -1997,12 +2109,15 @@ static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio5_hwmod = {
        .name           = "gpio5",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap44xx_gpio5_irqs,
        .main_clk       = "gpio5_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_GPIO5_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_GPIO5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio5_opt_clks,
@@ -2050,12 +2165,15 @@ static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
 static struct omap_hwmod omap44xx_gpio6_hwmod = {
        .name           = "gpio6",
        .class          = &omap44xx_gpio_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap44xx_gpio6_irqs,
        .main_clk       = "gpio6_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_GPIO6_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_GPIO6_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = gpio6_opt_clks,
@@ -2129,11 +2247,14 @@ static struct omap_hwmod_ocp_if *omap44xx_hsi_slaves[] = {
 static struct omap_hwmod omap44xx_hsi_hwmod = {
        .name           = "hsi",
        .class          = &omap44xx_hsi_hwmod_class,
+       .clkdm_name     = "l3_init_clkdm",
        .mpu_irqs       = omap44xx_hsi_irqs,
        .main_clk       = "hsi_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INIT_HSI_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .slaves         = omap44xx_hsi_slaves,
@@ -2209,13 +2330,16 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = {
 static struct omap_hwmod omap44xx_i2c1_hwmod = {
        .name           = "i2c1",
        .class          = &omap44xx_i2c_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c1_irqs,
        .sdma_reqs      = omap44xx_i2c1_sdma_reqs,
        .main_clk       = "i2c1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_I2C1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_I2C1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_i2c1_slaves,
@@ -2263,13 +2387,16 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = {
 static struct omap_hwmod omap44xx_i2c2_hwmod = {
        .name           = "i2c2",
        .class          = &omap44xx_i2c_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c2_irqs,
        .sdma_reqs      = omap44xx_i2c2_sdma_reqs,
        .main_clk       = "i2c2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_I2C2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_I2C2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_i2c2_slaves,
@@ -2317,13 +2444,16 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = {
 static struct omap_hwmod omap44xx_i2c3_hwmod = {
        .name           = "i2c3",
        .class          = &omap44xx_i2c_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c3_irqs,
        .sdma_reqs      = omap44xx_i2c3_sdma_reqs,
        .main_clk       = "i2c3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_I2C3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_I2C3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_i2c3_slaves,
@@ -2371,13 +2501,16 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = {
 static struct omap_hwmod omap44xx_i2c4_hwmod = {
        .name           = "i2c4",
        .class          = &omap44xx_i2c_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c4_irqs,
        .sdma_reqs      = omap44xx_i2c4_sdma_reqs,
        .main_clk       = "i2c4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_I2C4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_I2C4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_i2c4_slaves,
@@ -2435,12 +2568,13 @@ static struct omap_hwmod_ocp_if *omap44xx_ipu_slaves[] = {
 static struct omap_hwmod omap44xx_ipu_c0_hwmod = {
        .name           = "ipu_c0",
        .class          = &omap44xx_ipu_hwmod_class,
+       .clkdm_name     = "ducati_clkdm",
        .flags          = HWMOD_INIT_NO_RESET,
        .rst_lines      = omap44xx_ipu_c0_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_ipu_c0_resets),
        .prcm = {
                .omap4 = {
-                       .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+                       .rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
                },
        },
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -2450,12 +2584,13 @@ static struct omap_hwmod omap44xx_ipu_c0_hwmod = {
 static struct omap_hwmod omap44xx_ipu_c1_hwmod = {
        .name           = "ipu_c1",
        .class          = &omap44xx_ipu_hwmod_class,
+       .clkdm_name     = "ducati_clkdm",
        .flags          = HWMOD_INIT_NO_RESET,
        .rst_lines      = omap44xx_ipu_c1_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_ipu_c1_resets),
        .prcm = {
                .omap4 = {
-                       .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+                       .rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
                },
        },
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -2464,14 +2599,17 @@ static struct omap_hwmod omap44xx_ipu_c1_hwmod = {
 static struct omap_hwmod omap44xx_ipu_hwmod = {
        .name           = "ipu",
        .class          = &omap44xx_ipu_hwmod_class,
+       .clkdm_name     = "ducati_clkdm",
        .mpu_irqs       = omap44xx_ipu_irqs,
        .rst_lines      = omap44xx_ipu_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_ipu_resets),
        .main_clk       = "ipu_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
-                       .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+                       .clkctrl_offs = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET,
+                       .rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_DUCATI_DUCATI_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .slaves         = omap44xx_ipu_slaves,
@@ -2551,12 +2689,15 @@ static struct omap_hwmod_opt_clk iss_opt_clks[] = {
 static struct omap_hwmod omap44xx_iss_hwmod = {
        .name           = "iss",
        .class          = &omap44xx_iss_hwmod_class,
+       .clkdm_name     = "iss_clkdm",
        .mpu_irqs       = omap44xx_iss_irqs,
        .sdma_reqs      = omap44xx_iss_sdma_reqs,
        .main_clk       = "iss_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_CAM_ISS_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_CAM_ISS_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .opt_clks       = iss_opt_clks,
@@ -2631,12 +2772,13 @@ static struct omap_hwmod_ocp_if *omap44xx_iva_slaves[] = {
 static struct omap_hwmod omap44xx_iva_seq0_hwmod = {
        .name           = "iva_seq0",
        .class          = &omap44xx_iva_hwmod_class,
+       .clkdm_name     = "ivahd_clkdm",
        .flags          = HWMOD_INIT_NO_RESET,
        .rst_lines      = omap44xx_iva_seq0_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_iva_seq0_resets),
        .prcm = {
                .omap4 = {
-                       .rstctrl_reg = OMAP4430_RM_IVAHD_RSTCTRL,
+                       .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
                },
        },
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -2646,12 +2788,13 @@ static struct omap_hwmod omap44xx_iva_seq0_hwmod = {
 static struct omap_hwmod omap44xx_iva_seq1_hwmod = {
        .name           = "iva_seq1",
        .class          = &omap44xx_iva_hwmod_class,
+       .clkdm_name     = "ivahd_clkdm",
        .flags          = HWMOD_INIT_NO_RESET,
        .rst_lines      = omap44xx_iva_seq1_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_iva_seq1_resets),
        .prcm = {
                .omap4 = {
-                       .rstctrl_reg = OMAP4430_RM_IVAHD_RSTCTRL,
+                       .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
                },
        },
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -2660,14 +2803,17 @@ static struct omap_hwmod omap44xx_iva_seq1_hwmod = {
 static struct omap_hwmod omap44xx_iva_hwmod = {
        .name           = "iva",
        .class          = &omap44xx_iva_hwmod_class,
+       .clkdm_name     = "ivahd_clkdm",
        .mpu_irqs       = omap44xx_iva_irqs,
        .rst_lines      = omap44xx_iva_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_iva_resets),
        .main_clk       = "iva_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL,
-                       .rstctrl_reg = OMAP4430_RM_IVAHD_RSTCTRL,
+                       .clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET,
+                       .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_IVAHD_IVAHD_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .slaves         = omap44xx_iva_slaves,
@@ -2732,11 +2878,14 @@ static struct omap_hwmod_ocp_if *omap44xx_kbd_slaves[] = {
 static struct omap_hwmod omap44xx_kbd_hwmod = {
        .name           = "kbd",
        .class          = &omap44xx_kbd_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .mpu_irqs       = omap44xx_kbd_irqs,
        .main_clk       = "kbd_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_KEYBOARD_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_kbd_slaves,
@@ -2797,10 +2946,12 @@ static struct omap_hwmod_ocp_if *omap44xx_mailbox_slaves[] = {
 static struct omap_hwmod omap44xx_mailbox_hwmod = {
        .name           = "mailbox",
        .class          = &omap44xx_mailbox_hwmod_class,
+       .clkdm_name     = "l4_cfg_clkdm",
        .mpu_irqs       = omap44xx_mailbox_irqs,
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4CFG_MAILBOX_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
                },
        },
        .slaves         = omap44xx_mailbox_slaves,
@@ -2887,12 +3038,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mcbsp1_slaves[] = {
 static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
        .name           = "mcbsp1",
        .class          = &omap44xx_mcbsp_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_mcbsp1_irqs,
        .sdma_reqs      = omap44xx_mcbsp1_sdma_reqs,
        .main_clk       = "mcbsp1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_MCBSP1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mcbsp1_slaves,
@@ -2960,12 +3114,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mcbsp2_slaves[] = {
 static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
        .name           = "mcbsp2",
        .class          = &omap44xx_mcbsp_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_mcbsp2_irqs,
        .sdma_reqs      = omap44xx_mcbsp2_sdma_reqs,
        .main_clk       = "mcbsp2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_MCBSP2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mcbsp2_slaves,
@@ -3033,12 +3190,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mcbsp3_slaves[] = {
 static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
        .name           = "mcbsp3",
        .class          = &omap44xx_mcbsp_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_mcbsp3_irqs,
        .sdma_reqs      = omap44xx_mcbsp3_sdma_reqs,
        .main_clk       = "mcbsp3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_MCBSP3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mcbsp3_slaves,
@@ -3085,12 +3245,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mcbsp4_slaves[] = {
 static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
        .name           = "mcbsp4",
        .class          = &omap44xx_mcbsp_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mcbsp4_irqs,
        .sdma_reqs      = omap44xx_mcbsp4_sdma_reqs,
        .main_clk       = "mcbsp4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MCBSP4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mcbsp4_slaves,
@@ -3177,12 +3340,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
 static struct omap_hwmod omap44xx_mcpdm_hwmod = {
        .name           = "mcpdm",
        .class          = &omap44xx_mcpdm_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_mcpdm_irqs,
        .sdma_reqs      = omap44xx_mcpdm_sdma_reqs,
        .main_clk       = "mcpdm_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_PDM_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mcpdm_slaves,
@@ -3262,12 +3428,15 @@ static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
 static struct omap_hwmod omap44xx_mcspi1_hwmod = {
        .name           = "mcspi1",
        .class          = &omap44xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mcspi1_irqs,
        .sdma_reqs      = omap44xx_mcspi1_sdma_reqs,
        .main_clk       = "mcspi1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .dev_attr       = &mcspi1_dev_attr,
@@ -3322,12 +3491,15 @@ static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
 static struct omap_hwmod omap44xx_mcspi2_hwmod = {
        .name           = "mcspi2",
        .class          = &omap44xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mcspi2_irqs,
        .sdma_reqs      = omap44xx_mcspi2_sdma_reqs,
        .main_clk       = "mcspi2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .dev_attr       = &mcspi2_dev_attr,
@@ -3382,12 +3554,15 @@ static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
 static struct omap_hwmod omap44xx_mcspi3_hwmod = {
        .name           = "mcspi3",
        .class          = &omap44xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mcspi3_irqs,
        .sdma_reqs      = omap44xx_mcspi3_sdma_reqs,
        .main_clk       = "mcspi3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .dev_attr       = &mcspi3_dev_attr,
@@ -3440,12 +3615,15 @@ static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
 static struct omap_hwmod omap44xx_mcspi4_hwmod = {
        .name           = "mcspi4",
        .class          = &omap44xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mcspi4_irqs,
        .sdma_reqs      = omap44xx_mcspi4_sdma_reqs,
        .main_clk       = "mcspi4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .dev_attr       = &mcspi4_dev_attr,
@@ -3524,12 +3702,15 @@ static struct omap_mmc_dev_attr mmc1_dev_attr = {
 static struct omap_hwmod omap44xx_mmc1_hwmod = {
        .name           = "mmc1",
        .class          = &omap44xx_mmc_hwmod_class,
+       .clkdm_name     = "l3_init_clkdm",
        .mpu_irqs       = omap44xx_mmc1_irqs,
        .sdma_reqs      = omap44xx_mmc1_sdma_reqs,
        .main_clk       = "mmc1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L3INIT_MMC1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INIT_MMC1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .dev_attr       = &mmc1_dev_attr,
@@ -3583,12 +3764,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mmc2_slaves[] = {
 static struct omap_hwmod omap44xx_mmc2_hwmod = {
        .name           = "mmc2",
        .class          = &omap44xx_mmc_hwmod_class,
+       .clkdm_name     = "l3_init_clkdm",
        .mpu_irqs       = omap44xx_mmc2_irqs,
        .sdma_reqs      = omap44xx_mmc2_sdma_reqs,
        .main_clk       = "mmc2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L3INIT_MMC2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INIT_MMC2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mmc2_slaves,
@@ -3637,12 +3821,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mmc3_slaves[] = {
 static struct omap_hwmod omap44xx_mmc3_hwmod = {
        .name           = "mmc3",
        .class          = &omap44xx_mmc_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mmc3_irqs,
        .sdma_reqs      = omap44xx_mmc3_sdma_reqs,
        .main_clk       = "mmc3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MMCSD3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mmc3_slaves,
@@ -3689,13 +3876,16 @@ static struct omap_hwmod_ocp_if *omap44xx_mmc4_slaves[] = {
 static struct omap_hwmod omap44xx_mmc4_hwmod = {
        .name           = "mmc4",
        .class          = &omap44xx_mmc_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mmc4_irqs,
 
        .sdma_reqs      = omap44xx_mmc4_sdma_reqs,
        .main_clk       = "mmc4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MMCSD4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mmc4_slaves,
@@ -3742,12 +3932,15 @@ static struct omap_hwmod_ocp_if *omap44xx_mmc5_slaves[] = {
 static struct omap_hwmod omap44xx_mmc5_hwmod = {
        .name           = "mmc5",
        .class          = &omap44xx_mmc_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_mmc5_irqs,
        .sdma_reqs      = omap44xx_mmc5_sdma_reqs,
        .main_clk       = "mmc5_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD5_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_MMCSD5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_mmc5_slaves,
@@ -3782,12 +3975,14 @@ static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
 static struct omap_hwmod omap44xx_mpu_hwmod = {
        .name           = "mpu",
        .class          = &omap44xx_mpu_hwmod_class,
+       .clkdm_name     = "mpuss_clkdm",
        .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
        .mpu_irqs       = omap44xx_mpu_irqs,
        .main_clk       = "dpll_mpu_m2_ck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
                },
        },
        .masters        = omap44xx_mpu_masters,
@@ -3854,13 +4049,16 @@ static struct omap_hwmod_ocp_if *omap44xx_smartreflex_core_slaves[] = {
 static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
        .name           = "smartreflex_core",
        .class          = &omap44xx_smartreflex_hwmod_class,
+       .clkdm_name     = "l4_ao_clkdm",
        .mpu_irqs       = omap44xx_smartreflex_core_irqs,
 
        .main_clk       = "smartreflex_core_fck",
        .vdd_name       = "core",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ALWON_SR_CORE_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_smartreflex_core_slaves,
@@ -3901,12 +4099,15 @@ static struct omap_hwmod_ocp_if *omap44xx_smartreflex_iva_slaves[] = {
 static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
        .name           = "smartreflex_iva",
        .class          = &omap44xx_smartreflex_hwmod_class,
+       .clkdm_name     = "l4_ao_clkdm",
        .mpu_irqs       = omap44xx_smartreflex_iva_irqs,
        .main_clk       = "smartreflex_iva_fck",
        .vdd_name       = "iva",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ALWON_SR_IVA_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_smartreflex_iva_slaves,
@@ -3947,12 +4148,15 @@ static struct omap_hwmod_ocp_if *omap44xx_smartreflex_mpu_slaves[] = {
 static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
        .name           = "smartreflex_mpu",
        .class          = &omap44xx_smartreflex_hwmod_class,
+       .clkdm_name     = "l4_ao_clkdm",
        .mpu_irqs       = omap44xx_smartreflex_mpu_irqs,
        .main_clk       = "smartreflex_mpu_fck",
        .vdd_name       = "mpu",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ALWON_SR_MPU_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_smartreflex_mpu_slaves,
@@ -4011,9 +4215,11 @@ static struct omap_hwmod_ocp_if *omap44xx_spinlock_slaves[] = {
 static struct omap_hwmod omap44xx_spinlock_hwmod = {
        .name           = "spinlock",
        .class          = &omap44xx_spinlock_hwmod_class,
+       .clkdm_name     = "l4_cfg_clkdm",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4CFG_HW_SEM_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4CFG_HW_SEM_CONTEXT_OFFSET,
                },
        },
        .slaves         = omap44xx_spinlock_slaves,
@@ -4092,11 +4298,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer1_slaves[] = {
 static struct omap_hwmod omap44xx_timer1_hwmod = {
        .name           = "timer1",
        .class          = &omap44xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .mpu_irqs       = omap44xx_timer1_irqs,
        .main_clk       = "timer1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_TIMER1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer1_slaves,
@@ -4137,11 +4346,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer2_slaves[] = {
 static struct omap_hwmod omap44xx_timer2_hwmod = {
        .name           = "timer2",
        .class          = &omap44xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer2_irqs,
        .main_clk       = "timer2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer2_slaves,
@@ -4182,11 +4394,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer3_slaves[] = {
 static struct omap_hwmod omap44xx_timer3_hwmod = {
        .name           = "timer3",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer3_irqs,
        .main_clk       = "timer3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer3_slaves,
@@ -4227,11 +4442,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer4_slaves[] = {
 static struct omap_hwmod omap44xx_timer4_hwmod = {
        .name           = "timer4",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer4_irqs,
        .main_clk       = "timer4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer4_slaves,
@@ -4291,11 +4509,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer5_slaves[] = {
 static struct omap_hwmod omap44xx_timer5_hwmod = {
        .name           = "timer5",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_timer5_irqs,
        .main_clk       = "timer5_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_TIMER5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer5_slaves,
@@ -4355,12 +4576,15 @@ static struct omap_hwmod_ocp_if *omap44xx_timer6_slaves[] = {
 static struct omap_hwmod omap44xx_timer6_hwmod = {
        .name           = "timer6",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_timer6_irqs,
 
        .main_clk       = "timer6_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_TIMER6_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer6_slaves,
@@ -4420,11 +4644,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer7_slaves[] = {
 static struct omap_hwmod omap44xx_timer7_hwmod = {
        .name           = "timer7",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_timer7_irqs,
        .main_clk       = "timer7_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_TIMER7_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer7_slaves,
@@ -4484,11 +4711,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer8_slaves[] = {
 static struct omap_hwmod omap44xx_timer8_hwmod = {
        .name           = "timer8",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_timer8_irqs,
        .main_clk       = "timer8_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_TIMER8_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer8_slaves,
@@ -4529,11 +4759,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer9_slaves[] = {
 static struct omap_hwmod omap44xx_timer9_hwmod = {
        .name           = "timer9",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer9_irqs,
        .main_clk       = "timer9_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER9_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer9_slaves,
@@ -4574,11 +4807,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer10_slaves[] = {
 static struct omap_hwmod omap44xx_timer10_hwmod = {
        .name           = "timer10",
        .class          = &omap44xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer10_irqs,
        .main_clk       = "timer10_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER10_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer10_slaves,
@@ -4619,11 +4855,14 @@ static struct omap_hwmod_ocp_if *omap44xx_timer11_slaves[] = {
 static struct omap_hwmod omap44xx_timer11_hwmod = {
        .name           = "timer11",
        .class          = &omap44xx_timer_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_timer11_irqs,
        .main_clk       = "timer11_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_DMTIMER11_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_timer11_slaves,
@@ -4692,12 +4931,15 @@ static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
 static struct omap_hwmod omap44xx_uart1_hwmod = {
        .name           = "uart1",
        .class          = &omap44xx_uart_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_uart1_irqs,
        .sdma_reqs      = omap44xx_uart1_sdma_reqs,
        .main_clk       = "uart1_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_UART1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_uart1_slaves,
@@ -4744,12 +4986,15 @@ static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
 static struct omap_hwmod omap44xx_uart2_hwmod = {
        .name           = "uart2",
        .class          = &omap44xx_uart_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_uart2_irqs,
        .sdma_reqs      = omap44xx_uart2_sdma_reqs,
        .main_clk       = "uart2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_UART2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_uart2_slaves,
@@ -4796,13 +5041,16 @@ static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
 static struct omap_hwmod omap44xx_uart3_hwmod = {
        .name           = "uart3",
        .class          = &omap44xx_uart_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
        .mpu_irqs       = omap44xx_uart3_irqs,
        .sdma_reqs      = omap44xx_uart3_sdma_reqs,
        .main_clk       = "uart3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_UART3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_uart3_slaves,
@@ -4849,12 +5097,15 @@ static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
 static struct omap_hwmod omap44xx_uart4_hwmod = {
        .name           = "uart4",
        .class          = &omap44xx_uart_hwmod_class,
+       .clkdm_name     = "l4_per_clkdm",
        .mpu_irqs       = omap44xx_uart4_irqs,
        .sdma_reqs      = omap44xx_uart4_sdma_reqs,
        .main_clk       = "uart4_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L4PER_UART4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_uart4_slaves,
@@ -4927,12 +5178,15 @@ static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
 static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
        .name           = "usb_otg_hs",
        .class          = &omap44xx_usb_otg_hs_hwmod_class,
+       .clkdm_name     = "l3_init_clkdm",
        .flags          = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
        .mpu_irqs       = omap44xx_usb_otg_hs_irqs,
        .main_clk       = "usb_otg_hs_ick",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_L3INIT_USB_OTG_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
                },
        },
        .opt_clks       = usb_otg_hs_opt_clks,
@@ -5000,11 +5254,14 @@ static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
 static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
        .name           = "wd_timer2",
        .class          = &omap44xx_wd_timer_hwmod_class,
+       .clkdm_name     = "l4_wkup_clkdm",
        .mpu_irqs       = omap44xx_wd_timer2_irqs,
        .main_clk       = "wd_timer2_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_WKUP_WDT2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_wd_timer2_slaves,
@@ -5064,11 +5321,14 @@ static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
 static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
        .name           = "wd_timer3",
        .class          = &omap44xx_wd_timer_hwmod_class,
+       .clkdm_name     = "abe_clkdm",
        .mpu_irqs       = omap44xx_wd_timer3_irqs,
        .main_clk       = "wd_timer3_fck",
        .prcm = {
                .omap4 = {
-                       .clkctrl_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+                       .clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
+                       .context_offs = OMAP4_RM_ABE_WDT3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
                },
        },
        .slaves         = omap44xx_wd_timer3_slaves,
index d48813fd62de9a539db7f258970f9cc1da204924..3feb35911a325576bf7a6f57892adbcccbeda853 100644 (file)
@@ -108,6 +108,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
        u32 cur_state;
        int sleep_switch = -1;
        int ret = 0;
+       int hwsup = 0;
 
        if (pwrdm == NULL || IS_ERR(pwrdm))
                return -EINVAL;
@@ -127,6 +128,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
                        (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
                        sleep_switch = LOWPOWERSTATE_SWITCH;
                } else {
+                       hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
                        clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
                        pwrdm_wait_transition(pwrdm);
                        sleep_switch = FORCEWAKEUP_SWITCH;
@@ -142,7 +144,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
 
        switch (sleep_switch) {
        case FORCEWAKEUP_SWITCH:
-               if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO)
+               if (hwsup)
                        clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
                else
                        clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
index 6be14389e4f3412a579750f7c056dbec99714d5e..2e40a5cf016393d031033ea128c33c6448678403 100644 (file)
@@ -70,7 +70,7 @@ static void omap_prcm_arch_reset(char mode, const char *cmd)
                prcm_offs = OMAP3430_GR_MOD;
                omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0));
        } else if (cpu_is_omap44xx()) {
-               omap4_prm_global_warm_sw_reset(); /* never returns */
+               omap4_prminst_global_warm_sw_reset(); /* never returns */
        } else {
                WARN_ON(1);
        }
index a2a04bfa962855820c4f1a1576e9546ae87ef8c6..00165558fc4dab9c016bf80d4d69928e78f9aabf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * OMAP4 PRM module functions
  *
- * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2011 Texas Instruments, Inc.
  * Copyright (C) 2010 Nokia Corporation
  * Benoît Cousson
  * Paul Walmsley
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
 
-/*
- * Address offset (in bytes) between the reset control and the reset
- * status registers: 4 bytes on OMAP4
- */
-#define OMAP4_RST_CTRL_ST_OFFSET               4
-
 /* PRM low-level functions */
 
 /* Read a register in a CM/PRM instance in the PRM module */
@@ -56,140 +50,3 @@ u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg)
 
        return v;
 }
-
-/* Read a PRM register, AND it, and shift the result down to bit 0 */
-/* XXX deprecated */
-u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask)
-{
-       u32 v;
-
-       v = __raw_readl(reg);
-       v &= mask;
-       v >>= __ffs(mask);
-
-       return v;
-}
-
-/* Read-modify-write a register in a PRM module. Caller must lock */
-/* XXX deprecated */
-u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg)
-{
-       u32 v;
-
-       v = __raw_readl(reg);
-       v &= ~mask;
-       v |= bits;
-       __raw_writel(v, reg);
-
-       return v;
-}
-
-u32 omap4_prm_set_inst_reg_bits(u32 bits, s16 inst, s16 reg)
-{
-       return omap4_prm_rmw_inst_reg_bits(bits, bits, inst, reg);
-}
-
-u32 omap4_prm_clear_inst_reg_bits(u32 bits, s16 inst, s16 reg)
-{
-       return omap4_prm_rmw_inst_reg_bits(bits, 0x0, inst, reg);
-}
-
-/**
- * omap4_prm_is_hardreset_asserted - read the HW reset line state of
- * submodules contained in the hwmod module
- * @rstctrl_reg: RM_RSTCTRL register address for this module
- * @shift: register bit shift corresponding to the reset line to check
- *
- * Returns 1 if the (sub)module hardreset line is currently asserted,
- * 0 if the (sub)module hardreset line is not currently asserted, or
- * -EINVAL upon parameter error.
- */
-int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift)
-{
-       if (!cpu_is_omap44xx() || !rstctrl_reg)
-               return -EINVAL;
-
-       return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift));
-}
-
-/**
- * omap4_prm_assert_hardreset - assert the HW reset line of a submodule
- * @rstctrl_reg: RM_RSTCTRL register address for this module
- * @shift: register bit shift corresponding to the reset line to assert
- *
- * Some IPs like dsp, ipu or iva contain processors that require an HW
- * reset line to be asserted / deasserted in order to fully enable the
- * IP.  These modules may have multiple hard-reset lines that reset
- * different 'submodules' inside the IP block.  This function will
- * place the submodule into reset.  Returns 0 upon success or -EINVAL
- * upon an argument error.
- */
-int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift)
-{
-       u32 mask;
-
-       if (!cpu_is_omap44xx() || !rstctrl_reg)
-               return -EINVAL;
-
-       mask = 1 << shift;
-       omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg);
-
-       return 0;
-}
-
-/**
- * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait
- * @rstctrl_reg: RM_RSTCTRL register address for this module
- * @shift: register bit shift corresponding to the reset line to deassert
- *
- * Some IPs like dsp, ipu or iva contain processors that require an HW
- * reset line to be asserted / deasserted in order to fully enable the
- * IP.  These modules may have multiple hard-reset lines that reset
- * different 'submodules' inside the IP block.  This function will
- * take the submodule out of reset and wait until the PRCM indicates
- * that the reset has completed before returning.  Returns 0 upon success or
- * -EINVAL upon an argument error, -EEXIST if the submodule was already out
- * of reset, or -EBUSY if the submodule did not exit reset promptly.
- */
-int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift)
-{
-       u32 mask;
-       void __iomem *rstst_reg;
-       int c;
-
-       if (!cpu_is_omap44xx() || !rstctrl_reg)
-               return -EINVAL;
-
-       rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET;
-
-       mask = 1 << shift;
-
-       /* Check the current status to avoid de-asserting the line twice */
-       if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0)
-               return -EEXIST;
-
-       /* Clear the reset status by writing 1 to the status bit */
-       omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg);
-       /* de-assert the reset control line */
-       omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg);
-       /* wait the status to be set */
-       omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask),
-                         MAX_MODULE_HARDRESET_WAIT, c);
-
-       return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
-}
-
-void omap4_prm_global_warm_sw_reset(void)
-{
-       u32 v;
-
-       v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
-                                   OMAP4_RM_RSTCTRL);
-       v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
-       omap4_prm_write_inst_reg(v, OMAP4430_PRM_DEVICE_INST,
-                                OMAP4_RM_RSTCTRL);
-
-       /* OCP barrier */
-       v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
-                                   OMAP4_RM_RSTCTRL);
-}
index 6e53120fd6cb5e4ae395bb38b9a5134f93330545..7dfa379b625d987820abcb4ad66e510856b07e61 100644 (file)
 extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx);
 extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx);
 extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
-extern u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg);
-extern u32 omap4_prm_set_inst_reg_bits(u32 bits, s16 inst, s16 idx);
-extern u32 omap4_prm_clear_inst_reg_bits(u32 bits, s16 inst, s16 idx);
-extern u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask);
-
-extern int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift);
-extern int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift);
-extern int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift);
-
-extern void omap4_prm_global_warm_sw_reset(void);
 
 # endif
 
index a303242972786b227e46dd181d2e74467cac6674..3a7bab16edd5b4326d38fdfa93b00b82aa2a10ef 100644 (file)
@@ -2,6 +2,7 @@
  * OMAP4 PRM instance functions
  *
  * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
@@ -53,7 +54,7 @@ void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx)
 
 /* Read-modify-write a register in PRM. Caller must lock */
 u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
-                                  s16 idx)
+                                   u16 idx)
 {
        u32 v;
 
@@ -64,3 +65,112 @@ u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
 
        return v;
 }
+
+/*
+ * Address offset (in bytes) between the reset control and the reset
+ * status registers: 4 bytes on OMAP4
+ */
+#define OMAP4_RST_CTRL_ST_OFFSET               4
+
+/**
+ * omap4_prminst_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL upon parameter error.
+ */
+int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
+                                       u16 rstctrl_offs)
+{
+       u32 v;
+
+       v = omap4_prminst_read_inst_reg(part, inst, rstctrl_offs);
+       v &= 1 << shift;
+       v >>= shift;
+
+       return v;
+}
+
+/**
+ * omap4_prminst_assert_hardreset - assert the HW reset line of a submodule
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * place the submodule into reset.  Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
+                                  u16 rstctrl_offs)
+{
+       u32 mask = 1 << shift;
+
+       omap4_prminst_rmw_inst_reg_bits(mask, mask, part, inst, rstctrl_offs);
+
+       return 0;
+}
+
+/**
+ * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and
+ * wait
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning.  Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst,
+                                    u16 rstctrl_offs)
+{
+       int c;
+       u32 mask = 1 << shift;
+       u16 rstst_offs = rstctrl_offs + OMAP4_RST_CTRL_ST_OFFSET;
+
+       /* Check the current status to avoid de-asserting the line twice */
+       if (omap4_prminst_is_hardreset_asserted(shift, part, inst,
+                                               rstctrl_offs) == 0)
+               return -EEXIST;
+
+       /* Clear the reset status by writing 1 to the status bit */
+       omap4_prminst_rmw_inst_reg_bits(0xffffffff, mask, part, inst,
+                                       rstst_offs);
+       /* de-assert the reset control line */
+       omap4_prminst_rmw_inst_reg_bits(mask, 0, part, inst, rstctrl_offs);
+       /* wait the status to be set */
+       omap_test_timeout(omap4_prminst_is_hardreset_asserted(shift, part, inst,
+                                                             rstst_offs),
+                         MAX_MODULE_HARDRESET_WAIT, c);
+
+       return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
+
+void omap4_prminst_global_warm_sw_reset(void)
+{
+       u32 v;
+
+       v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
+                                   OMAP4430_PRM_DEVICE_INST,
+                                   OMAP4_PRM_RSTCTRL_OFFSET);
+       v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
+       omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
+                                OMAP4430_PRM_DEVICE_INST,
+                                OMAP4_PRM_RSTCTRL_OFFSET);
+
+       /* OCP barrier */
+       v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
+                                   OMAP4430_PRM_DEVICE_INST,
+                                   OMAP4_PRM_RSTCTRL_OFFSET);
+}
index 02dd66ddda8bf4e9135b9d75cfede731761a70a1..46f2efb3659660bfd83dad39161a66035fd32163 100644 (file)
@@ -2,6 +2,7 @@
  * OMAP4 Power/Reset Management (PRM) function prototypes
  *
  * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * This program is free software; you can redistribute it and/or modify
 extern u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx);
 extern void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx);
 extern u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part,
-                                          s16 inst, s16 idx);
+                                          s16 inst, u16 idx);
 
-extern void omap4_prm_global_warm_sw_reset(void);
+extern void omap4_prminst_global_warm_sw_reset(void);
+
+extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
+                                              u16 rstctrl_offs);
+extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
+                                         u16 rstctrl_offs);
+extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst,
+                                           u16 rstctrl_offs);
 
 #endif
index 3aaa46f6cd12efefd587f6d6c0a7ba08c3bc4c9c..2543342dbccb2532d391921c2651f4b764fe53c4 100644 (file)
@@ -80,11 +80,11 @@ static struct twl4030_madc_platform_data omap3_madc_pdata = {
        .irq_line       = 1,
 };
 
-static struct twl4030_codec_audio_data omap3_audio;
+static struct twl4030_codec_data omap3_codec;
 
-static struct twl4030_codec_data omap3_codec_pdata = {
+static struct twl4030_audio_data omap3_audio_pdata = {
        .audio_mclk = 26000000,
-       .audio = &omap3_audio,
+       .codec = &omap3_codec,
 };
 
 static struct regulator_consumer_supply omap3_vdda_dac_supplies[] = {
@@ -292,8 +292,8 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
        if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc)
                pmic_data->madc = &omap3_madc_pdata;
 
-       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->codec)
-               pmic_data->codec = &omap3_codec_pdata;
+       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
+               pmic_data->audio = &omap3_audio_pdata;
 
        /* Common regulator configurations */
        if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
index 964704f40bbeecd80ffa646eb4008ce9657b86c8..3ba4d11ca73e25b53be83ccb883319d3f0560af7 100644 (file)
@@ -475,8 +475,41 @@ int __init clk_init(struct clk_functions * custom_clocks)
 /*
  *     debugfs support to trace clock tree hierarchy and attributes
  */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
 static struct dentry *clk_debugfs_root;
 
+static int clk_dbg_show_summary(struct seq_file *s, void *unused)
+{
+       struct clk *c;
+       struct clk *pa;
+
+       seq_printf(s, "%-30s %-30s %-10s %s\n",
+               "clock-name", "parent-name", "rate", "use-count");
+
+       list_for_each_entry(c, &clocks, node) {
+               pa = c->parent;
+               seq_printf(s, "%-30s %-30s %-10lu %d\n",
+                       c->name, pa ? pa->name : "none", c->rate, c->usecount);
+       }
+
+       return 0;
+}
+
+static int clk_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, clk_dbg_show_summary, inode->i_private);
+}
+
+static const struct file_operations debug_clock_fops = {
+       .open           = clk_dbg_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int clk_debugfs_register_one(struct clk *c)
 {
        int err;
@@ -545,6 +578,12 @@ static int __init clk_debugfs_init(void)
                if (err)
                        goto err_out;
        }
+
+       d = debugfs_create_file("summary", S_IRUGO,
+               d, NULL, &debug_clock_fops);
+       if (!d)
+               return -ENOMEM;
+
        return 0;
 err_out:
        debugfs_remove_recursive(clk_debugfs_root);
index c88432005665418b1897559461862d7c17fc4d8f..926d25c780f35eb648def7168d71b8d4827e05af 100644 (file)
 #endif
 #define TWL6030_IRQ_END                (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS)
 
+#define TWL6040_CODEC_IRQ_BASE TWL6030_IRQ_END
+#ifdef CONFIG_TWL6040_CODEC
+#define TWL6040_CODEC_NR_IRQS  6
+#else
+#define TWL6040_CODEC_NR_IRQS  0
+#endif
+#define TWL6040_CODEC_IRQ_END  (TWL6040_CODEC_IRQ_BASE + TWL6040_CODEC_NR_IRQS)
+
 /* Total number of interrupts depends on the enabled blocks above */
-#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END)
+#if (TWL4030_GPIO_IRQ_END > TWL6040_CODEC_IRQ_END)
 #define TWL_IRQ_END            TWL4030_GPIO_IRQ_END
 #else
-#define TWL_IRQ_END            TWL6030_IRQ_END
+#define TWL_IRQ_END            TWL6040_CODEC_IRQ_END
 #endif
 
 /* GPMC related */
index fafdfe3c8d4e8e92d3f4a9f610e30d8f38935fa8..0e329ca88a70f8d56acd8d35ac053e51bd185623 100644 (file)
@@ -2,6 +2,7 @@
  * omap_hwmod macros, structures
  *
  * Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
  * Paul Walmsley
  *
  * Created in collaboration with (alphabetical order): Benoît Cousson,
@@ -79,6 +80,11 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2;
 #define HWMOD_IDLEMODE_SMART           (1 << 2)
 #define HWMOD_IDLEMODE_SMART_WKUP      (1 << 3)
 
+/* modulemode control type (SW or HW) */
+#define MODULEMODE_HWCTRL              1
+#define MODULEMODE_SWCTRL              2
+
+
 /**
  * struct omap_hwmod_mux_info - hwmod specific mux configuration
  * @pads:              array of omap_device_pad entries
@@ -360,9 +366,11 @@ struct omap_hwmod_omap2_prcm {
  * @submodule_wkdep_bit: bit shift of the WKDEP range
  */
 struct omap_hwmod_omap4_prcm {
-       void __iomem    *clkctrl_reg;
-       void __iomem    *rstctrl_reg;
+       u16             clkctrl_offs;
+       u16             rstctrl_offs;
+       u16             context_offs;
        u8              submodule_wkdep_bit;
+       u8              modulemode;
 };
 
 
@@ -515,6 +523,8 @@ struct omap_hwmod {
        const char                      *main_clk;
        struct clk                      *_clk;
        struct omap_hwmod_opt_clk       *opt_clks;
+       char                            *clkdm_name;
+       struct clockdomain              *clkdm;
        char                            *vdd_name;
        struct voltagedomain            *voltdm;
        struct omap_hwmod_ocp_if        **masters; /* connect to *_IA */
index 3471c650743b656f47e0d7015987b07556ba2b9d..b6b40974495469314b3bec6faaf2cbeae981ea25 100644 (file)
@@ -236,56 +236,71 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
        return 0;
 }
 
+static void _add_clkdev(struct omap_device *od, const char *clk_alias,
+                      const char *clk_name)
+{
+       struct clk *r;
+       struct clk_lookup *l;
+
+       if (!clk_alias || !clk_name)
+               return;
+
+       pr_debug("omap_device: %s: Creating %s -> %s\n",
+                dev_name(&od->pdev.dev), clk_alias, clk_name);
+
+       r = clk_get_sys(dev_name(&od->pdev.dev), clk_alias);
+       if (!IS_ERR(r)) {
+               pr_warning("omap_device: %s: alias %s already exists\n",
+                          dev_name(&od->pdev.dev), clk_alias);
+               clk_put(r);
+               return;
+       }
+
+       r = omap_clk_get_by_name(clk_name);
+       if (IS_ERR(r)) {
+               pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n",
+                      dev_name(&od->pdev.dev), clk_name);
+               return;
+       }
+
+       l = clkdev_alloc(r, clk_alias, dev_name(&od->pdev.dev));
+       if (!l) {
+               pr_err("omap_device: %s: clkdev_alloc for %s failed\n",
+                      dev_name(&od->pdev.dev), clk_alias);
+               return;
+       }
+
+       clkdev_add(l);
+}
+
 /**
- * _add_optional_clock_clkdev - Add clkdev entry for hwmod optional clocks
+ * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
+ * and main clock
  * @od: struct omap_device *od
+ * @oh: struct omap_hwmod *oh
  *
- * For every optional clock present per hwmod per omap_device, this function
- * adds an entry in the clkdev table of the form <dev-id=dev_name, con-id=role>
- * if it does not exist already.
+ * For the main clock and every optional clock present per hwmod per
+ * omap_device, this function adds an entry in the clkdev table of the
+ * form <dev-id=dev_name, con-id=role> if it does not exist already.
  *
  * The function is called from inside omap_device_build_ss(), after
  * omap_device_register.
  *
  * This allows drivers to get a pointer to its optional clocks based on its role
  * by calling clk_get(<dev*>, <role>).
+ * In the case of the main clock, a "fck" alias is used.
  *
  * No return value.
  */
-static void _add_optional_clock_clkdev(struct omap_device *od,
-                                     struct omap_hwmod *oh)
+static void _add_hwmod_clocks_clkdev(struct omap_device *od,
+                                    struct omap_hwmod *oh)
 {
        int i;
 
-       for (i = 0; i < oh->opt_clks_cnt; i++) {
-               struct omap_hwmod_opt_clk *oc;
-               struct clk *r;
-               struct clk_lookup *l;
-
-               oc = &oh->opt_clks[i];
-
-               if (!oc->_clk)
-                       continue;
-
-               r = clk_get_sys(dev_name(&od->pdev.dev), oc->role);
-               if (!IS_ERR(r))
-                       continue; /* clkdev entry exists */
+       _add_clkdev(od, "fck", oh->main_clk);
 
-               r = omap_clk_get_by_name((char *)oc->clk);
-               if (IS_ERR(r)) {
-                       pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n",
-                              dev_name(&od->pdev.dev), oc->clk);
-                       continue;
-               }
-
-               l = clkdev_alloc(r, oc->role, dev_name(&od->pdev.dev));
-               if (!l) {
-                       pr_err("omap_device: %s: clkdev_alloc for %s failed\n",
-                              dev_name(&od->pdev.dev), oc->role);
-                       return;
-               }
-               clkdev_add(l);
-       }
+       for (i = 0; i < oh->opt_clks_cnt; i++)
+               _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
 }
 
 
@@ -492,7 +507,7 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
 
        for (i = 0; i < oh_cnt; i++) {
                hwmods[i]->od = od;
-               _add_optional_clock_clkdev(od, hwmods[i]);
+               _add_hwmod_clocks_clkdev(od, hwmods[i]);
        }
 
        if (ret)
index 45dc6aa62ba4fce3715c20b504da7f02745997e5..d1bf8724b58f79a7a8bed9cf567a0f24e53e6fed 100644 (file)
@@ -267,7 +267,7 @@ config INPUT_TWL4030_PWRBUTTON
 config INPUT_TWL4030_VIBRA
        tristate "Support for TWL4030 Vibrator"
        depends on TWL4030_CORE
-       select TWL4030_CODEC
+       select MFD_TWL4030_AUDIO
        select INPUT_FF_MEMLESS
        help
          This option enables support for TWL4030 Vibrator Driver.
@@ -275,6 +275,17 @@ config INPUT_TWL4030_VIBRA
          To compile this driver as a module, choose M here. The module will
          be called twl4030_vibra.
 
+config INPUT_TWL6040_VIBRA
+       tristate "Support for TWL6040 Vibrator"
+       depends on TWL4030_CORE
+       select TWL6040_CORE
+       select INPUT_FF_MEMLESS
+       help
+         This option enables support for TWL6040 Vibrator Driver.
+
+         To compile this driver as a module, choose M here. The module will
+         be called twl6040_vibra.
+
 config INPUT_UINPUT
        tristate "User level driver support"
        help
index 38efb2cb182b90646e7e4e7e41288e0222fca641..4da7c3a60e04b2b0f77832d6b31a3424c5c3d9d6 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS)          += sgi_btns.o
 obj-$(CONFIG_INPUT_SPARCSPKR)          += sparcspkr.o
 obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)  += twl4030-pwrbutton.o
 obj-$(CONFIG_INPUT_TWL4030_VIBRA)      += twl4030-vibra.o
+obj-$(CONFIG_INPUT_TWL6040_VIBRA)      += twl6040-vibra.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)          += wm831x-on.o
index 014dd4ad0d4fecede04221e5348fc78e023d76e2..3c1a432c14dc3a8f5eadd4540f247d669ba773dd 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
 #include <linux/i2c/twl.h>
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
 #include <linux/input.h>
 #include <linux/slab.h>
 
@@ -67,7 +67,7 @@ static void vibra_enable(struct vibra_info *info)
 {
        u8 reg;
 
-       twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER);
+       twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
 
        /* turn H-Bridge on */
        twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
@@ -75,7 +75,7 @@ static void vibra_enable(struct vibra_info *info)
        twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                         (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
 
-       twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
+       twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL);
 
        info->enabled = true;
 }
@@ -90,8 +90,8 @@ static void vibra_disable(struct vibra_info *info)
        twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                         (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
 
-       twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
-       twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
+       twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL);
+       twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
 
        info->enabled = false;
 }
@@ -196,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
 
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
+       struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
        struct vibra_info *info;
        int ret;
 
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
new file mode 100644 (file)
index 0000000..c43002e
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * twl6040-vibra.c - TWL6040 Vibrator driver
+ *
+ * Author:      Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ * Author:      Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright:   (C) 2011 Texas Instruments, Inc.
+ *
+ * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com>
+ *                             Felipe Balbi <felipe.balbi@nokia.com>
+ *                             Jari Vanhala <ext-javi.vanhala@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#define EFFECT_DIR_180_DEG     0x8000
+
+/* Recommended modulation index 85% */
+#define TWL6040_VIBRA_MOD      85
+
+#define TWL6040_NUM_SUPPLIES 2
+
+struct vibra_info {
+       struct device *dev;
+       struct input_dev *input_dev;
+       struct workqueue_struct *workqueue;
+       struct work_struct play_work;
+       struct mutex mutex;
+       int irq;
+
+       bool enabled;
+       int weak_speed;
+       int strong_speed;
+       int direction;
+
+       unsigned int vibldrv_res;
+       unsigned int vibrdrv_res;
+       unsigned int viblmotor_res;
+       unsigned int vibrmotor_res;
+
+       struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES];
+
+       struct twl6040 *twl6040;
+};
+
+static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
+{
+       struct vibra_info *info = data;
+       struct twl6040 *twl6040 = info->twl6040;
+       u8 status;
+
+       status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
+       if (status & TWL6040_VIBLOCDET) {
+               dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
+               twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
+                                  TWL6040_VIBENAL);
+       }
+       if (status & TWL6040_VIBROCDET) {
+               dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
+               twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
+                                  TWL6040_VIBENAR);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void twl6040_vibra_enable(struct vibra_info *info)
+{
+       struct twl6040 *twl6040 = info->twl6040;
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies);
+       if (ret) {
+               dev_err(info->dev, "failed to enable regulators %d\n", ret);
+               return;
+       }
+
+       twl6040_power(info->twl6040, 1);
+       if (twl6040->rev <= TWL6040_REV_ES1_1) {
+               /*
+                * ERRATA: Disable overcurrent protection for at least
+                * 3ms when enabling vibrator drivers to avoid false
+                * overcurrent detection
+                */
+               twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
+                                 TWL6040_VIBENAL | TWL6040_VIBCTRLL);
+               twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
+                                 TWL6040_VIBENAR | TWL6040_VIBCTRLR);
+               usleep_range(3000, 3500);
+       }
+
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
+                         TWL6040_VIBENAL);
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
+                         TWL6040_VIBENAR);
+
+       info->enabled = true;
+}
+
+static void twl6040_vibra_disable(struct vibra_info *info)
+{
+       struct twl6040 *twl6040 = info->twl6040;
+
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00);
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00);
+       twl6040_power(info->twl6040, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies);
+
+       info->enabled = false;
+}
+
+static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res,
+                            int speed, int direction)
+{
+       int vpk, max_code;
+       u8 vibdat;
+
+       /* output swing */
+       vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) /
+               (100 * (vibdrv_res + motor_res));
+
+       /* 50mV per VIBDAT code step */
+       max_code = vpk / 50;
+       if (max_code > TWL6040_VIBDAT_MAX)
+               max_code = TWL6040_VIBDAT_MAX;
+
+       /* scale speed to max allowed code */
+       vibdat = (u8)((speed * max_code) / USHRT_MAX);
+
+       /* 2's complement for direction > 180 degrees */
+       vibdat *= direction;
+
+       return vibdat;
+}
+
+static void twl6040_vibra_set_effect(struct vibra_info *info)
+{
+       struct twl6040 *twl6040 = info->twl6040;
+       u8 vibdatl, vibdatr;
+       int volt;
+
+       /* weak motor */
+       volt = regulator_get_voltage(info->supplies[0].consumer) / 1000;
+       vibdatl = twl6040_vibra_code(volt, info->vibldrv_res,
+                                    info->viblmotor_res,
+                                    info->weak_speed, info->direction);
+
+       /* strong motor */
+       volt = regulator_get_voltage(info->supplies[1].consumer) / 1000;
+       vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res,
+                                    info->vibrmotor_res,
+                                    info->strong_speed, info->direction);
+
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl);
+       twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr);
+}
+
+static void vibra_play_work(struct work_struct *work)
+{
+       struct vibra_info *info = container_of(work,
+                               struct vibra_info, play_work);
+
+       mutex_lock(&info->mutex);
+
+       if (info->weak_speed || info->strong_speed) {
+               if (!info->enabled)
+                       twl6040_vibra_enable(info);
+
+               twl6040_vibra_set_effect(info);
+       } else if (info->enabled)
+               twl6040_vibra_disable(info);
+
+       mutex_unlock(&info->mutex);
+}
+
+static int vibra_play(struct input_dev *input, void *data,
+                     struct ff_effect *effect)
+{
+       struct vibra_info *info = input_get_drvdata(input);
+       int ret;
+
+       info->weak_speed = effect->u.rumble.weak_magnitude;
+       info->strong_speed = effect->u.rumble.strong_magnitude;
+       info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
+
+       ret = queue_work(info->workqueue, &info->play_work);
+       if (!ret) {
+               dev_info(&input->dev, "work is already on queue\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void twl6040_vibra_close(struct input_dev *input)
+{
+       struct vibra_info *info = input_get_drvdata(input);
+
+       cancel_work_sync(&info->play_work);
+
+       mutex_lock(&info->mutex);
+
+       if (info->enabled)
+               twl6040_vibra_disable(info);
+
+       mutex_unlock(&info->mutex);
+}
+
+#if CONFIG_PM_SLEEP
+static int twl6040_vibra_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vibra_info *info = platform_get_drvdata(pdev);
+
+       mutex_lock(&info->mutex);
+
+       if (info->enabled)
+               twl6040_vibra_disable(info);
+
+       mutex_unlock(&info->mutex);
+
+       return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
+
+static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
+{
+       struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
+       struct vibra_info *info;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "platform_data not available\n");
+               return -EINVAL;
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "couldn't allocate memory\n");
+               return -ENOMEM;
+       }
+
+       info->dev = &pdev->dev;
+       info->twl6040 = dev_get_drvdata(pdev->dev.parent);
+       info->vibldrv_res = pdata->vibldrv_res;
+       info->vibrdrv_res = pdata->vibrdrv_res;
+       info->viblmotor_res = pdata->viblmotor_res;
+       info->vibrmotor_res = pdata->vibrmotor_res;
+       if ((!info->vibldrv_res && !info->viblmotor_res) ||
+           (!info->vibrdrv_res && !info->vibrmotor_res)) {
+               dev_err(info->dev, "invalid vibra driver/motor resistance\n");
+               ret = -EINVAL;
+               goto err_kzalloc;
+       }
+
+       info->irq = platform_get_irq(pdev, 0);
+       if (info->irq < 0) {
+               dev_err(info->dev, "invalid irq\n");
+               ret = -EINVAL;
+               goto err_kzalloc;
+       }
+
+       mutex_init(&info->mutex);
+
+       info->input_dev = input_allocate_device();
+       if (info->input_dev == NULL) {
+               dev_err(info->dev, "couldn't allocate input device\n");
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
+
+       input_set_drvdata(info->input_dev, info);
+
+       info->input_dev->name = "twl6040:vibrator";
+       info->input_dev->id.version = 1;
+       info->input_dev->dev.parent = pdev->dev.parent;
+       info->input_dev->close = twl6040_vibra_close;
+       __set_bit(FF_RUMBLE, info->input_dev->ffbit);
+
+       ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+       if (ret < 0) {
+               dev_err(info->dev, "couldn't register vibrator to FF\n");
+               goto err_ialloc;
+       }
+
+       ret = input_register_device(info->input_dev);
+       if (ret < 0) {
+               dev_err(info->dev, "couldn't register input device\n");
+               goto err_iff;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0,
+                                  "twl6040_irq_vib", info);
+       if (ret) {
+               dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
+               goto err_irq;
+       }
+
+       info->supplies[0].supply = "vddvibl";
+       info->supplies[1].supply = "vddvibr";
+       ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies),
+                                info->supplies);
+       if (ret) {
+               dev_err(info->dev, "couldn't get regulators %d\n", ret);
+               goto err_regulator;
+       }
+
+       if (pdata->vddvibl_uV) {
+               ret = regulator_set_voltage(info->supplies[0].consumer,
+                                           pdata->vddvibl_uV,
+                                           pdata->vddvibl_uV);
+               if (ret) {
+                       dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
+                               ret);
+                       goto err_voltage;
+               }
+       }
+
+       if (pdata->vddvibr_uV) {
+               ret = regulator_set_voltage(info->supplies[1].consumer,
+                                           pdata->vddvibr_uV,
+                                           pdata->vddvibr_uV);
+               if (ret) {
+                       dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
+                               ret);
+                       goto err_voltage;
+               }
+       }
+
+       info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
+       if (info->workqueue == NULL) {
+               dev_err(info->dev, "couldn't create workqueue\n");
+               ret = -ENOMEM;
+               goto err_voltage;
+       }
+       INIT_WORK(&info->play_work, vibra_play_work);
+
+       return 0;
+
+err_voltage:
+       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
+err_regulator:
+       free_irq(info->irq, info);
+err_irq:
+       input_unregister_device(info->input_dev);
+       info->input_dev = NULL;
+err_iff:
+       if (info->input_dev)
+               input_ff_destroy(info->input_dev);
+err_ialloc:
+       input_free_device(info->input_dev);
+err_kzalloc:
+       kfree(info);
+       return ret;
+}
+
+static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
+{
+       struct vibra_info *info = platform_get_drvdata(pdev);
+
+       input_unregister_device(info->input_dev);
+       free_irq(info->irq, info);
+       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
+       destroy_workqueue(info->workqueue);
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver twl6040_vibra_driver = {
+       .probe          = twl6040_vibra_probe,
+       .remove         = __devexit_p(twl6040_vibra_remove),
+       .driver         = {
+               .name   = "twl6040-vibra",
+               .owner  = THIS_MODULE,
+               .pm     = &twl6040_vibra_pm_ops,
+       },
+};
+
+static int __init twl6040_vibra_init(void)
+{
+       return platform_driver_register(&twl6040_vibra_driver);
+}
+module_init(twl6040_vibra_init);
+
+static void __exit twl6040_vibra_exit(void)
+{
+       platform_driver_unregister(&twl6040_vibra_driver);
+}
+module_exit(twl6040_vibra_exit);
+
+MODULE_ALIAS("platform:twl6040-vibra");
+MODULE_DESCRIPTION("TWL6040 Vibra driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
index 6ca938a6bf94d336ddbfd830c02bc4739436ffc9..37b83eb6d703fd782d9f24f9b4763b9a3be683c8 100644 (file)
@@ -218,7 +218,7 @@ config TWL4030_POWER
          and load scripts controlling which resources are switched off/on
          or reset when a sleep, wakeup or warm reset event occurs.
 
-config TWL4030_CODEC
+config MFD_TWL4030_AUDIO
        bool
        depends on TWL4030_CORE
        select MFD_CORE
@@ -233,6 +233,12 @@ config TWL6030_PWM
          Say yes here if you want support for TWL6030 PWM.
          This is used to control charging LED brightness.
 
+config TWL6040_CORE
+       bool
+       depends on TWL4030_CORE && GENERIC_HARDIRQS
+       select MFD_CORE
+       default n
+
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
        depends on I2C=y && GENERIC_HARDIRQS
index d7d47d2a4c7615c17d4aec23080692f2b603dda7..22a280fcb7059436966400a4a71caaecfd390ece 100644 (file)
@@ -40,8 +40,9 @@ obj-$(CONFIG_MENELAUS)                += menelaus.o
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
 obj-$(CONFIG_TWL4030_MADC)      += twl4030-madc.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
-obj-$(CONFIG_TWL4030_CODEC)    += twl4030-codec.o
+obj-$(CONFIG_MFD_TWL4030_AUDIO)        += twl4030-audio.o
 obj-$(CONFIG_TWL6030_PWM)      += twl6030-pwm.o
+obj-$(CONFIG_TWL6040_CORE)     += twl6040-core.o twl6040-irq.o
 
 obj-$(CONFIG_MFD_MC13XXX)      += mc13xxx-core.o
 
index b8f2a4e7f6e767f47da933edd805ffd0bdba2120..a2eddc70995cdfc789651548ad58fde1659c4488 100644 (file)
 #endif
 
 #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
-       defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE)
+       defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
 #define twl_has_codec()        true
 #else
 #define twl_has_codec()        false
@@ -815,20 +815,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        return PTR_ERR(child);
        }
 
-       if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
+       if (twl_has_codec() && pdata->audio && twl_class_is_4030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
                child = add_child(sub_chip_id, "twl4030-audio",
-                               pdata->codec, sizeof(*pdata->codec),
+                               pdata->audio, sizeof(*pdata->audio),
                                false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
-       /* Phoenix codec driver is probed directly atm */
-       if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
+       if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl6040-codec",
-                               pdata->codec, sizeof(*pdata->codec),
+               child = add_child(sub_chip_id, "twl6040",
+                               pdata->audio, sizeof(*pdata->audio),
                                false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c
new file mode 100644 (file)
index 0000000..ae51ab5
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * MFD driver for twl4030 audio submodule, which contains an audio codec, and
+ * the vibra control.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl4030-audio.h>
+
+#define TWL4030_AUDIO_CELLS    2
+
+static struct platform_device *twl4030_audio_dev;
+
+struct twl4030_audio_resource {
+       int request_count;
+       u8 reg;
+       u8 mask;
+};
+
+struct twl4030_audio {
+       unsigned int audio_mclk;
+       struct mutex mutex;
+       struct twl4030_audio_resource resource[TWL4030_AUDIO_RES_MAX];
+       struct mfd_cell cells[TWL4030_AUDIO_CELLS];
+};
+
+/*
+ * Modify the resource, the function returns the content of the register
+ * after the modification.
+ */
+static int twl4030_audio_set_resource(enum twl4030_audio_res id, int enable)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
+       u8 val;
+
+       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
+                       audio->resource[id].reg);
+
+       if (enable)
+               val |= audio->resource[id].mask;
+       else
+               val &= ~audio->resource[id].mask;
+
+       twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       val, audio->resource[id].reg);
+
+       return val;
+}
+
+static inline int twl4030_audio_get_resource(enum twl4030_audio_res id)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
+       u8 val;
+
+       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
+                       audio->resource[id].reg);
+
+       return val;
+}
+
+/*
+ * Enable the resource.
+ * The function returns with error or the content of the register
+ */
+int twl4030_audio_enable_resource(enum twl4030_audio_res id)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
+       int val;
+
+       if (id >= TWL4030_AUDIO_RES_MAX) {
+               dev_err(&twl4030_audio_dev->dev,
+                               "Invalid resource ID (%u)\n", id);
+               return -EINVAL;
+       }
+
+       mutex_lock(&audio->mutex);
+       if (!audio->resource[id].request_count)
+               /* Resource was disabled, enable it */
+               val = twl4030_audio_set_resource(id, 1);
+       else
+               val = twl4030_audio_get_resource(id);
+
+       audio->resource[id].request_count++;
+       mutex_unlock(&audio->mutex);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(twl4030_audio_enable_resource);
+
+/*
+ * Disable the resource.
+ * The function returns with error or the content of the register
+ */
+int twl4030_audio_disable_resource(unsigned id)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
+       int val;
+
+       if (id >= TWL4030_AUDIO_RES_MAX) {
+               dev_err(&twl4030_audio_dev->dev,
+                               "Invalid resource ID (%u)\n", id);
+               return -EINVAL;
+       }
+
+       mutex_lock(&audio->mutex);
+       if (!audio->resource[id].request_count) {
+               dev_err(&twl4030_audio_dev->dev,
+                       "Resource has been disabled already (%u)\n", id);
+               mutex_unlock(&audio->mutex);
+               return -EPERM;
+       }
+       audio->resource[id].request_count--;
+
+       if (!audio->resource[id].request_count)
+               /* Resource can be disabled now */
+               val = twl4030_audio_set_resource(id, 0);
+       else
+               val = twl4030_audio_get_resource(id);
+
+       mutex_unlock(&audio->mutex);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(twl4030_audio_disable_resource);
+
+unsigned int twl4030_audio_get_mclk(void)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev);
+
+       return audio->audio_mclk;
+}
+EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk);
+
+static int __devinit twl4030_audio_probe(struct platform_device *pdev)
+{
+       struct twl4030_audio *audio;
+       struct twl4030_audio_data *pdata = pdev->dev.platform_data;
+       struct mfd_cell *cell = NULL;
+       int ret, childs = 0;
+       u8 val;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Platform data is missing\n");
+               return -EINVAL;
+       }
+
+       /* Configure APLL_INFREQ and disable APLL if enabled */
+       val = 0;
+       switch (pdata->audio_mclk) {
+       case 19200000:
+               val |= TWL4030_APLL_INFREQ_19200KHZ;
+               break;
+       case 26000000:
+               val |= TWL4030_APLL_INFREQ_26000KHZ;
+               break;
+       case 38400000:
+               val |= TWL4030_APLL_INFREQ_38400KHZ;
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid audio_mclk\n");
+               return -EINVAL;
+       }
+       twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       val, TWL4030_REG_APLL_CTL);
+
+       audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL);
+       if (!audio)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, audio);
+
+       twl4030_audio_dev = pdev;
+       mutex_init(&audio->mutex);
+       audio->audio_mclk = pdata->audio_mclk;
+
+       /* Codec power */
+       audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
+       audio->resource[TWL4030_AUDIO_RES_POWER].mask = TWL4030_CODECPDZ;
+
+       /* PLL */
+       audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL;
+       audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN;
+
+       if (pdata->codec) {
+               cell = &audio->cells[childs];
+               cell->name = "twl4030-codec";
+               cell->platform_data = pdata->codec;
+               cell->pdata_size = sizeof(*pdata->codec);
+               childs++;
+       }
+       if (pdata->vibra) {
+               cell = &audio->cells[childs];
+               cell->name = "twl4030-vibra";
+               cell->platform_data = pdata->vibra;
+               cell->pdata_size = sizeof(*pdata->vibra);
+               childs++;
+       }
+
+       if (childs)
+               ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells,
+                                     childs, NULL, 0);
+       else {
+               dev_err(&pdev->dev, "No platform data found for childs\n");
+               ret = -ENODEV;
+       }
+
+       if (!ret)
+               return 0;
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(audio);
+       twl4030_audio_dev = NULL;
+       return ret;
+}
+
+static int __devexit twl4030_audio_remove(struct platform_device *pdev)
+{
+       struct twl4030_audio *audio = platform_get_drvdata(pdev);
+
+       mfd_remove_devices(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(audio);
+       twl4030_audio_dev = NULL;
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:twl4030-audio");
+
+static struct platform_driver twl4030_audio_driver = {
+       .probe          = twl4030_audio_probe,
+       .remove         = __devexit_p(twl4030_audio_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl4030-audio",
+       },
+};
+
+static int __devinit twl4030_audio_init(void)
+{
+       return platform_driver_register(&twl4030_audio_driver);
+}
+module_init(twl4030_audio_init);
+
+static void __devexit twl4030_audio_exit(void)
+{
+       platform_driver_unregister(&twl4030_audio_driver);
+}
+module_exit(twl4030_audio_exit);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c
deleted file mode 100644 (file)
index 2bf4136..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * MFD driver for twl4030 codec submodule
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * Copyright:   (C) 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/i2c/twl.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/twl4030-codec.h>
-
-#define TWL4030_CODEC_CELLS    2
-
-static struct platform_device *twl4030_codec_dev;
-
-struct twl4030_codec_resource {
-       int request_count;
-       u8 reg;
-       u8 mask;
-};
-
-struct twl4030_codec {
-       unsigned int audio_mclk;
-       struct mutex mutex;
-       struct twl4030_codec_resource resource[TWL4030_CODEC_RES_MAX];
-       struct mfd_cell cells[TWL4030_CODEC_CELLS];
-};
-
-/*
- * Modify the resource, the function returns the content of the register
- * after the modification.
- */
-static int twl4030_codec_set_resource(enum twl4030_codec_res id, int enable)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
-       u8 val;
-
-       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
-                       codec->resource[id].reg);
-
-       if (enable)
-               val |= codec->resource[id].mask;
-       else
-               val &= ~codec->resource[id].mask;
-
-       twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                       val, codec->resource[id].reg);
-
-       return val;
-}
-
-static inline int twl4030_codec_get_resource(enum twl4030_codec_res id)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
-       u8 val;
-
-       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
-                       codec->resource[id].reg);
-
-       return val;
-}
-
-/*
- * Enable the resource.
- * The function returns with error or the content of the register
- */
-int twl4030_codec_enable_resource(enum twl4030_codec_res id)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
-       int val;
-
-       if (id >= TWL4030_CODEC_RES_MAX) {
-               dev_err(&twl4030_codec_dev->dev,
-                               "Invalid resource ID (%u)\n", id);
-               return -EINVAL;
-       }
-
-       mutex_lock(&codec->mutex);
-       if (!codec->resource[id].request_count)
-               /* Resource was disabled, enable it */
-               val = twl4030_codec_set_resource(id, 1);
-       else
-               val = twl4030_codec_get_resource(id);
-
-       codec->resource[id].request_count++;
-       mutex_unlock(&codec->mutex);
-
-       return val;
-}
-EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource);
-
-/*
- * Disable the resource.
- * The function returns with error or the content of the register
- */
-int twl4030_codec_disable_resource(unsigned id)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
-       int val;
-
-       if (id >= TWL4030_CODEC_RES_MAX) {
-               dev_err(&twl4030_codec_dev->dev,
-                               "Invalid resource ID (%u)\n", id);
-               return -EINVAL;
-       }
-
-       mutex_lock(&codec->mutex);
-       if (!codec->resource[id].request_count) {
-               dev_err(&twl4030_codec_dev->dev,
-                       "Resource has been disabled already (%u)\n", id);
-               mutex_unlock(&codec->mutex);
-               return -EPERM;
-       }
-       codec->resource[id].request_count--;
-
-       if (!codec->resource[id].request_count)
-               /* Resource can be disabled now */
-               val = twl4030_codec_set_resource(id, 0);
-       else
-               val = twl4030_codec_get_resource(id);
-
-       mutex_unlock(&codec->mutex);
-
-       return val;
-}
-EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource);
-
-unsigned int twl4030_codec_get_mclk(void)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
-
-       return codec->audio_mclk;
-}
-EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk);
-
-static int __devinit twl4030_codec_probe(struct platform_device *pdev)
-{
-       struct twl4030_codec *codec;
-       struct twl4030_codec_data *pdata = pdev->dev.platform_data;
-       struct mfd_cell *cell = NULL;
-       int ret, childs = 0;
-       u8 val;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "Platform data is missing\n");
-               return -EINVAL;
-       }
-
-       /* Configure APLL_INFREQ and disable APLL if enabled */
-       val = 0;
-       switch (pdata->audio_mclk) {
-       case 19200000:
-               val |= TWL4030_APLL_INFREQ_19200KHZ;
-               break;
-       case 26000000:
-               val |= TWL4030_APLL_INFREQ_26000KHZ;
-               break;
-       case 38400000:
-               val |= TWL4030_APLL_INFREQ_38400KHZ;
-               break;
-       default:
-               dev_err(&pdev->dev, "Invalid audio_mclk\n");
-               return -EINVAL;
-       }
-       twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                       val, TWL4030_REG_APLL_CTL);
-
-       codec = kzalloc(sizeof(struct twl4030_codec), GFP_KERNEL);
-       if (!codec)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, codec);
-
-       twl4030_codec_dev = pdev;
-       mutex_init(&codec->mutex);
-       codec->audio_mclk = pdata->audio_mclk;
-
-       /* Codec power */
-       codec->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
-       codec->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ;
-
-       /* PLL */
-       codec->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL;
-       codec->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN;
-
-       if (pdata->audio) {
-               cell = &codec->cells[childs];
-               cell->name = "twl4030-codec";
-               cell->platform_data = pdata->audio;
-               cell->pdata_size = sizeof(*pdata->audio);
-               childs++;
-       }
-       if (pdata->vibra) {
-               cell = &codec->cells[childs];
-               cell->name = "twl4030-vibra";
-               cell->platform_data = pdata->vibra;
-               cell->pdata_size = sizeof(*pdata->vibra);
-               childs++;
-       }
-
-       if (childs)
-               ret = mfd_add_devices(&pdev->dev, pdev->id, codec->cells,
-                                     childs, NULL, 0);
-       else {
-               dev_err(&pdev->dev, "No platform data found for childs\n");
-               ret = -ENODEV;
-       }
-
-       if (!ret)
-               return 0;
-
-       platform_set_drvdata(pdev, NULL);
-       kfree(codec);
-       twl4030_codec_dev = NULL;
-       return ret;
-}
-
-static int __devexit twl4030_codec_remove(struct platform_device *pdev)
-{
-       struct twl4030_codec *codec = platform_get_drvdata(pdev);
-
-       mfd_remove_devices(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
-       kfree(codec);
-       twl4030_codec_dev = NULL;
-
-       return 0;
-}
-
-MODULE_ALIAS("platform:twl4030-audio");
-
-static struct platform_driver twl4030_codec_driver = {
-       .probe          = twl4030_codec_probe,
-       .remove         = __devexit_p(twl4030_codec_remove),
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "twl4030-audio",
-       },
-};
-
-static int __devinit twl4030_codec_init(void)
-{
-       return platform_driver_register(&twl4030_codec_driver);
-}
-module_init(twl4030_codec_init);
-
-static void __devexit twl4030_codec_exit(void)
-{
-       platform_driver_unregister(&twl4030_codec_driver);
-}
-module_exit(twl4030_codec_exit);
-
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
new file mode 100644 (file)
index 0000000..24d436c
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * MFD driver for TWL6040 audio device
+ *
+ * Authors:    Misael Lopez Cruz <misael.lopez@ti.com>
+ *             Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ *             Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Copyright:  (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl6040.h>
+
+static struct platform_device *twl6040_dev;
+
+int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
+{
+       int ret;
+       u8 val = 0;
+
+       mutex_lock(&twl6040->io_mutex);
+       ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+       if (ret < 0) {
+               mutex_unlock(&twl6040->io_mutex);
+               return ret;
+       }
+       mutex_unlock(&twl6040->io_mutex);
+
+       return val;
+}
+EXPORT_SYMBOL(twl6040_reg_read);
+
+int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
+{
+       int ret;
+
+       mutex_lock(&twl6040->io_mutex);
+       ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+       mutex_unlock(&twl6040->io_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(twl6040_reg_write);
+
+int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
+{
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl6040->io_mutex);
+       ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+       if (ret)
+               goto out;
+
+       val |= mask;
+       ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+out:
+       mutex_unlock(&twl6040->io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(twl6040_set_bits);
+
+int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
+{
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl6040->io_mutex);
+       ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+       if (ret)
+               goto out;
+
+       val &= ~mask;
+       ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+out:
+       mutex_unlock(&twl6040->io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(twl6040_clear_bits);
+
+/* twl6040 codec manual power-up sequence */
+static int twl6040_power_up(struct twl6040 *twl6040)
+{
+       u8 ldoctl, ncpctl, lppllctl;
+       int ret;
+
+       /* enable high-side LDO, reference system and internal oscillator */
+       ldoctl = TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA;
+       ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+       if (ret)
+               return ret;
+       usleep_range(10000, 10500);
+
+       /* enable negative charge pump */
+       ncpctl = TWL6040_NCPENA;
+       ret = twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+       if (ret)
+               goto ncp_err;
+       usleep_range(1000, 1500);
+
+       /* enable low-side LDO */
+       ldoctl |= TWL6040_LSLDOENA;
+       ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+       if (ret)
+               goto lsldo_err;
+       usleep_range(1000, 1500);
+
+       /* enable low-power PLL */
+       lppllctl = TWL6040_LPLLENA;
+       ret = twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+       if (ret)
+               goto lppll_err;
+       usleep_range(5000, 5500);
+
+       /* disable internal oscillator */
+       ldoctl &= ~TWL6040_OSCENA;
+       ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+       if (ret)
+               goto osc_err;
+
+       return 0;
+
+osc_err:
+       lppllctl &= ~TWL6040_LPLLENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+lppll_err:
+       ldoctl &= ~TWL6040_LSLDOENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+lsldo_err:
+       ncpctl &= ~TWL6040_NCPENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+ncp_err:
+       ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA);
+       twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+
+       return ret;
+}
+
+/* twl6040 manual power-down sequence */
+static void twl6040_power_down(struct twl6040 *twl6040)
+{
+       u8 ncpctl, ldoctl, lppllctl;
+
+       ncpctl = twl6040_reg_read(twl6040, TWL6040_REG_NCPCTL);
+       ldoctl = twl6040_reg_read(twl6040, TWL6040_REG_LDOCTL);
+       lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+
+       /* enable internal oscillator */
+       ldoctl |= TWL6040_OSCENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+       usleep_range(1000, 1500);
+
+       /* disable low-power PLL */
+       lppllctl &= ~TWL6040_LPLLENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+       /* disable low-side LDO */
+       ldoctl &= ~TWL6040_LSLDOENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+
+       /* disable negative charge pump */
+       ncpctl &= ~TWL6040_NCPENA;
+       twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+
+       /* disable high-side LDO, reference system and internal oscillator */
+       ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA);
+       twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+}
+
+static irqreturn_t twl6040_naudint_handler(int irq, void *data)
+{
+       struct twl6040 *twl6040 = data;
+       u8 intid, status;
+
+       intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+       if (intid & TWL6040_READYINT)
+               complete(&twl6040->ready);
+
+       if (intid & TWL6040_THINT) {
+               status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
+               if (status & TWL6040_TSHUTDET) {
+                       dev_warn(&twl6040_dev->dev,
+                                "Thermal shutdown, powering-off");
+                       twl6040_power(twl6040, 0);
+               } else {
+                       dev_warn(&twl6040_dev->dev,
+                                "Leaving thermal shutdown, powering-on");
+                       twl6040_power(twl6040, 1);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int twl6040_power_up_completion(struct twl6040 *twl6040,
+                                      int naudint)
+{
+       int time_left;
+       u8 intid;
+
+       time_left = wait_for_completion_timeout(&twl6040->ready,
+                                               msecs_to_jiffies(144));
+       if (!time_left) {
+               intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+               if (!(intid & TWL6040_READYINT)) {
+                       dev_err(&twl6040_dev->dev,
+                               "timeout waiting for READYINT\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+int twl6040_power(struct twl6040 *twl6040, int on)
+{
+       int audpwron = twl6040->audpwron;
+       int naudint = twl6040->irq;
+       int ret = 0;
+
+       mutex_lock(&twl6040->mutex);
+
+       if (on) {
+               /* already powered-up */
+               if (twl6040->power_count++)
+                       goto out;
+
+               if (gpio_is_valid(audpwron)) {
+                       /* use AUDPWRON line */
+                       gpio_set_value(audpwron, 1);
+                       /* wait for power-up completion */
+                       ret = twl6040_power_up_completion(twl6040, naudint);
+                       if (ret) {
+                               dev_err(&twl6040_dev->dev,
+                                       "automatic power-down failed\n");
+                               twl6040->power_count = 0;
+                               goto out;
+                       }
+               } else {
+                       /* use manual power-up sequence */
+                       ret = twl6040_power_up(twl6040);
+                       if (ret) {
+                               dev_err(&twl6040_dev->dev,
+                                       "manual power-up failed\n");
+                               twl6040->power_count = 0;
+                               goto out;
+                       }
+               }
+               /* Default PLL configuration after power up */
+               twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
+               twl6040->sysclk = 19200000;
+       } else {
+               /* already powered-down */
+               if (!twl6040->power_count) {
+                       dev_err(&twl6040_dev->dev,
+                               "device is already powered-off\n");
+                       ret = -EPERM;
+                       goto out;
+               }
+
+               if (--twl6040->power_count)
+                       goto out;
+
+               if (gpio_is_valid(audpwron)) {
+                       /* use AUDPWRON line */
+                       gpio_set_value(audpwron, 0);
+
+                       /* power-down sequence latency */
+                       usleep_range(500, 700);
+               } else {
+                       /* use manual power-down sequence */
+                       twl6040_power_down(twl6040);
+               }
+               twl6040->sysclk = 0;
+       }
+
+out:
+       mutex_unlock(&twl6040->mutex);
+       return ret;
+}
+EXPORT_SYMBOL(twl6040_power);
+
+int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
+                   unsigned int freq_in, unsigned int freq_out)
+{
+       u8 hppllctl, lppllctl;
+       int ret = 0;
+
+       mutex_lock(&twl6040->mutex);
+
+       hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
+       lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+
+       switch (pll_id) {
+       case TWL6040_SYSCLK_SEL_LPPLL:
+               /* low-power PLL divider */
+               switch (freq_out) {
+               case 17640000:
+                       lppllctl |= TWL6040_LPLLFIN;
+                       break;
+               case 19200000:
+                       lppllctl &= ~TWL6040_LPLLFIN;
+                       break;
+               default:
+                       dev_err(&twl6040_dev->dev,
+                               "freq_out %d not supported\n", freq_out);
+                       ret = -EINVAL;
+                       goto pll_out;
+               }
+               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+               switch (freq_in) {
+               case 32768:
+                       lppllctl |= TWL6040_LPLLENA;
+                       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+                                         lppllctl);
+                       mdelay(5);
+                       lppllctl &= ~TWL6040_HPLLSEL;
+                       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+                                         lppllctl);
+                       hppllctl &= ~TWL6040_HPLLENA;
+                       twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
+                                         hppllctl);
+                       break;
+               default:
+                       dev_err(&twl6040_dev->dev,
+                               "freq_in %d not supported\n", freq_in);
+                       ret = -EINVAL;
+                       goto pll_out;
+               }
+               break;
+       case TWL6040_SYSCLK_SEL_HPPLL:
+               /* high-performance PLL can provide only 19.2 MHz */
+               if (freq_out != 19200000) {
+                       dev_err(&twl6040_dev->dev,
+                               "freq_out %d not supported\n", freq_out);
+                       ret = -EINVAL;
+                       goto pll_out;
+               }
+
+               hppllctl &= ~TWL6040_MCLK_MSK;
+
+               switch (freq_in) {
+               case 12000000:
+                       /* PLL enabled, active mode */
+                       hppllctl |= TWL6040_MCLK_12000KHZ |
+                                   TWL6040_HPLLENA;
+                       break;
+               case 19200000:
+                       /*
+                        * PLL disabled
+                        * (enable PLL if MCLK jitter quality
+                        *  doesn't meet specification)
+                        */
+                       hppllctl |= TWL6040_MCLK_19200KHZ;
+                       break;
+               case 26000000:
+                       /* PLL enabled, active mode */
+                       hppllctl |= TWL6040_MCLK_26000KHZ |
+                                   TWL6040_HPLLENA;
+                       break;
+               case 38400000:
+                       /* PLL enabled, active mode */
+                       hppllctl |= TWL6040_MCLK_38400KHZ |
+                                   TWL6040_HPLLENA;
+                       break;
+               default:
+                       dev_err(&twl6040_dev->dev,
+                               "freq_in %d not supported\n", freq_in);
+                       ret = -EINVAL;
+                       goto pll_out;
+               }
+
+               /* enable clock slicer to ensure input waveform is square */
+               hppllctl |= TWL6040_HPLLSQRENA;
+
+               twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl);
+               usleep_range(500, 700);
+               lppllctl |= TWL6040_HPLLSEL;
+               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+               lppllctl &= ~TWL6040_LPLLENA;
+               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+               break;
+       default:
+               dev_err(&twl6040_dev->dev, "unknown pll id %d\n", pll_id);
+               ret = -EINVAL;
+               goto pll_out;
+       }
+
+       twl6040->sysclk = freq_out;
+       twl6040->pll = pll_id;
+
+pll_out:
+       mutex_unlock(&twl6040->mutex);
+       return ret;
+}
+EXPORT_SYMBOL(twl6040_set_pll);
+
+int twl6040_get_pll(struct twl6040 *twl6040)
+{
+       if (twl6040->power_count)
+               return twl6040->pll;
+       else
+               return -ENODEV;
+}
+EXPORT_SYMBOL(twl6040_get_pll);
+
+unsigned int twl6040_get_sysclk(struct twl6040 *twl6040)
+{
+       return twl6040->sysclk;
+}
+EXPORT_SYMBOL(twl6040_get_sysclk);
+
+static struct resource twl6040_vibra_rsrc[] = {
+       {
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource twl6040_codec_rsrc[] = {
+       {
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static int __devinit twl6040_probe(struct platform_device *pdev)
+{
+       struct twl4030_audio_data *pdata = pdev->dev.platform_data;
+       struct twl6040 *twl6040;
+       struct mfd_cell *cell = NULL;
+       int ret, children = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Platform data is missing\n");
+               return -EINVAL;
+       }
+
+       /* In order to operate correctly we need valid interrupt config */
+       if (!pdata->naudint_irq || !pdata->irq_base) {
+               dev_err(&pdev->dev, "Invalid IRQ configuration\n");
+               return -EINVAL;
+       }
+
+       twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL);
+       if (!twl6040)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, twl6040);
+
+       twl6040_dev = pdev;
+       twl6040->dev = &pdev->dev;
+       twl6040->audpwron = pdata->audpwron_gpio;
+       twl6040->irq = pdata->naudint_irq;
+       twl6040->irq_base = pdata->irq_base;
+
+       mutex_init(&twl6040->mutex);
+       mutex_init(&twl6040->io_mutex);
+       init_completion(&twl6040->ready);
+
+       twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
+
+       if (gpio_is_valid(twl6040->audpwron)) {
+               ret = gpio_request(twl6040->audpwron, "audpwron");
+               if (ret)
+                       goto gpio1_err;
+
+               ret = gpio_direction_output(twl6040->audpwron, 0);
+               if (ret)
+                       goto gpio2_err;
+       }
+
+       /* ERRATA: Automatic power-up is not possible in ES1.0 */
+       if (twl6040->rev == TWL6040_REV_ES1_0)
+               twl6040->audpwron = -EINVAL;
+
+       /* codec interrupt */
+       ret = twl6040_irq_init(twl6040);
+       if (ret)
+               goto gpio2_err;
+
+       ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY,
+                                  NULL, twl6040_naudint_handler, 0,
+                                  "twl6040_irq_ready", twl6040);
+       if (ret) {
+               dev_err(twl6040->dev, "READY IRQ request failed: %d\n",
+                       ret);
+               goto irq_err;
+       }
+
+       /* dual-access registers controlled by I2C only */
+       twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
+
+       if (pdata->codec) {
+               int irq = twl6040->irq_base + TWL6040_IRQ_PLUG;
+
+               cell = &twl6040->cells[children];
+               cell->name = "twl6040-codec";
+               twl6040_codec_rsrc[0].start = irq;
+               twl6040_codec_rsrc[0].end = irq;
+               cell->resources = twl6040_codec_rsrc;
+               cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
+               cell->platform_data = pdata->codec;
+               cell->pdata_size = sizeof(*pdata->codec);
+               children++;
+       }
+
+       if (pdata->vibra) {
+               int irq = twl6040->irq_base + TWL6040_IRQ_VIB;
+
+               cell = &twl6040->cells[children];
+               cell->name = "twl6040-vibra";
+               twl6040_vibra_rsrc[0].start = irq;
+               twl6040_vibra_rsrc[0].end = irq;
+               cell->resources = twl6040_vibra_rsrc;
+               cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc);
+
+               cell->platform_data = pdata->vibra;
+               cell->pdata_size = sizeof(*pdata->vibra);
+               children++;
+       }
+
+       if (children) {
+               ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells,
+                                     children, NULL, 0);
+               if (ret)
+                       goto mfd_err;
+       } else {
+               dev_err(&pdev->dev, "No platform data found for children\n");
+               ret = -ENODEV;
+               goto mfd_err;
+       }
+
+       return 0;
+
+mfd_err:
+       free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
+irq_err:
+       twl6040_irq_exit(twl6040);
+gpio2_err:
+       if (gpio_is_valid(twl6040->audpwron))
+               gpio_free(twl6040->audpwron);
+gpio1_err:
+       platform_set_drvdata(pdev, NULL);
+       kfree(twl6040);
+       twl6040_dev = NULL;
+       return ret;
+}
+
+static int __devexit twl6040_remove(struct platform_device *pdev)
+{
+       struct twl6040 *twl6040 = platform_get_drvdata(pdev);
+
+       if (twl6040->power_count)
+               twl6040_power(twl6040, 0);
+
+       if (gpio_is_valid(twl6040->audpwron))
+               gpio_free(twl6040->audpwron);
+
+       free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
+       twl6040_irq_exit(twl6040);
+
+       mfd_remove_devices(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(twl6040);
+       twl6040_dev = NULL;
+
+       return 0;
+}
+
+static struct platform_driver twl6040_driver = {
+       .probe          = twl6040_probe,
+       .remove         = __devexit_p(twl6040_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl6040",
+       },
+};
+
+static int __devinit twl6040_init(void)
+{
+       return platform_driver_register(&twl6040_driver);
+}
+module_init(twl6040_init);
+
+static void __devexit twl6040_exit(void)
+{
+       platform_driver_unregister(&twl6040_driver);
+}
+
+module_exit(twl6040_exit);
+
+MODULE_DESCRIPTION("TWL6040 MFD");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl6040");
diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
new file mode 100644 (file)
index 0000000..b3f8dda
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Interrupt controller support for TWL6040
+ *
+ * Author:     Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright:   (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl6040.h>
+
+struct twl6040_irq_data {
+       int mask;
+       int status;
+};
+
+static struct twl6040_irq_data twl6040_irqs[] = {
+       {
+               .mask = TWL6040_THMSK,
+               .status = TWL6040_THINT,
+       },
+       {
+               .mask = TWL6040_PLUGMSK,
+               .status = TWL6040_PLUGINT | TWL6040_UNPLUGINT,
+       },
+       {
+               .mask = TWL6040_HOOKMSK,
+               .status = TWL6040_HOOKINT,
+       },
+       {
+               .mask = TWL6040_HFMSK,
+               .status = TWL6040_HFINT,
+       },
+       {
+               .mask = TWL6040_VIBMSK,
+               .status = TWL6040_VIBINT,
+       },
+       {
+               .mask = TWL6040_READYMSK,
+               .status = TWL6040_READYINT,
+       },
+};
+
+static inline
+struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040,
+                                           int irq)
+{
+       return &twl6040_irqs[irq - twl6040->irq_base];
+}
+
+static void twl6040_irq_lock(struct irq_data *data)
+{
+       struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&twl6040->irq_mutex);
+}
+
+static void twl6040_irq_sync_unlock(struct irq_data *data)
+{
+       struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
+
+       /* write back to hardware any change in irq mask */
+       if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) {
+               twl6040->irq_masks_cache = twl6040->irq_masks_cur;
+               twl6040_reg_write(twl6040, TWL6040_REG_INTMR,
+                                 twl6040->irq_masks_cur);
+       }
+
+       mutex_unlock(&twl6040->irq_mutex);
+}
+
+static void twl6040_irq_enable(struct irq_data *data)
+{
+       struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
+       struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
+                                                              data->irq);
+
+       twl6040->irq_masks_cur &= ~irq_data->mask;
+}
+
+static void twl6040_irq_disable(struct irq_data *data)
+{
+       struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
+       struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
+                                                              data->irq);
+
+       twl6040->irq_masks_cur |= irq_data->mask;
+}
+
+static struct irq_chip twl6040_irq_chip = {
+       .name                   = "twl6040",
+       .irq_bus_lock           = twl6040_irq_lock,
+       .irq_bus_sync_unlock    = twl6040_irq_sync_unlock,
+       .irq_enable             = twl6040_irq_enable,
+       .irq_disable            = twl6040_irq_disable,
+};
+
+static irqreturn_t twl6040_irq_thread(int irq, void *data)
+{
+       struct twl6040 *twl6040 = data;
+       u8 intid;
+       int i;
+
+       intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+       /* apply masking and report (backwards to handle READYINT first) */
+       for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) {
+               if (twl6040->irq_masks_cur & twl6040_irqs[i].mask)
+                       intid &= ~twl6040_irqs[i].status;
+               if (intid & twl6040_irqs[i].status)
+                       handle_nested_irq(twl6040->irq_base + i);
+       }
+
+       /* ack unmasked irqs */
+       twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid);
+
+       return IRQ_HANDLED;
+}
+
+int twl6040_irq_init(struct twl6040 *twl6040)
+{
+       int cur_irq, ret;
+       u8 val;
+
+       mutex_init(&twl6040->irq_mutex);
+
+       /* mask the individual interrupt sources */
+       twl6040->irq_masks_cur = TWL6040_ALLINT_MSK;
+       twl6040->irq_masks_cache = TWL6040_ALLINT_MSK;
+       twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);
+
+       /* Register them with genirq */
+       for (cur_irq = twl6040->irq_base;
+            cur_irq < twl6040->irq_base + ARRAY_SIZE(twl6040_irqs);
+            cur_irq++) {
+               irq_set_chip_data(cur_irq, twl6040);
+               irq_set_chip_and_handler(cur_irq, &twl6040_irq_chip,
+                                        handle_level_irq);
+               irq_set_nested_thread(cur_irq, 1);
+
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               irq_set_noprobe(cur_irq);
+#endif
+       }
+
+       ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread,
+                                  IRQF_ONESHOT, "twl6040", twl6040);
+       if (ret) {
+               dev_err(twl6040->dev, "failed to request IRQ %d: %d\n",
+                       twl6040->irq, ret);
+               return ret;
+       }
+
+       /* reset interrupts */
+       val = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+       /* interrupts cleared on write */
+       twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_INTCLRMODE);
+
+       return 0;
+}
+EXPORT_SYMBOL(twl6040_irq_init);
+
+void twl6040_irq_exit(struct twl6040 *twl6040)
+{
+       free_irq(twl6040->irq, twl6040);
+}
+EXPORT_SYMBOL(twl6040_irq_exit);
index ba4f88624fcd2321fbeffd11ce61ec983e81dd9d..114c0f6fc63d8f7c818f79459995c6844736993a 100644 (file)
@@ -657,28 +657,41 @@ struct twl4030_power_data {
 extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 
-struct twl4030_codec_audio_data {
+struct twl4030_codec_data {
        unsigned int digimic_delay; /* in ms */
        unsigned int ramp_delay_value;
        unsigned int offset_cncl_path;
        unsigned int check_defaults:1;
        unsigned int reset_registers:1;
        unsigned int hs_extmute:1;
+       u16 hs_left_step;
+       u16 hs_right_step;
+       u16 hf_left_step;
+       u16 hf_right_step;
        void (*set_hs_extmute)(int mute);
 };
 
-struct twl4030_codec_vibra_data {
+struct twl4030_vibra_data {
        unsigned int    coexist;
+
+       /* twl6040 */
+       unsigned int vibldrv_res;       /* left driver resistance */
+       unsigned int vibrdrv_res;       /* right driver resistance */
+       unsigned int viblmotor_res;     /* left motor resistance */
+       unsigned int vibrmotor_res;     /* right motor resistance */
+       int vddvibl_uV;                 /* VDDVIBL volt, set 0 for fixed reg */
+       int vddvibr_uV;                 /* VDDVIBR volt, set 0 for fixed reg */
 };
 
-struct twl4030_codec_data {
+struct twl4030_audio_data {
        unsigned int    audio_mclk;
-       struct twl4030_codec_audio_data         *audio;
-       struct twl4030_codec_vibra_data         *vibra;
+       struct twl4030_codec_data *codec;
+       struct twl4030_vibra_data *vibra;
 
        /* twl6040 */
        int audpwron_gpio;      /* audio power-on gpio */
        int naudint_irq;        /* audio interrupt */
+       unsigned int irq_base;
 };
 
 struct twl4030_platform_data {
@@ -690,7 +703,7 @@ struct twl4030_platform_data {
        struct twl4030_keypad_data              *keypad;
        struct twl4030_usb_data                 *usb;
        struct twl4030_power_data               *power;
-       struct twl4030_codec_data               *codec;
+       struct twl4030_audio_data               *audio;
 
        /* Common LDO regulators for TWL4030/TWL6030 */
        struct regulator_init_data              *vdac;
similarity index 96%
rename from include/linux/mfd/twl4030-codec.h
rename to include/linux/mfd/twl4030-audio.h
index 5cc16bbd1da1a855aaa924f25f1a6f0c716f97d5..3d22b72df076bc3ca2de9dc2b40263738b812fb1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * MFD driver for twl4030 codec submodule
+ * MFD driver for twl4030 audio submodule
  *
  * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
 #define TWL4030_VIBRA_DIR_SEL          0x20
 
 /* TWL4030 codec resource IDs */
-enum twl4030_codec_res {
-       TWL4030_CODEC_RES_POWER = 0,
-       TWL4030_CODEC_RES_APLL,
-       TWL4030_CODEC_RES_MAX,
+enum twl4030_audio_res {
+       TWL4030_AUDIO_RES_POWER = 0,
+       TWL4030_AUDIO_RES_APLL,
+       TWL4030_AUDIO_RES_MAX,
 };
 
-int twl4030_codec_disable_resource(enum twl4030_codec_res id);
-int twl4030_codec_enable_resource(enum twl4030_codec_res id);
-unsigned int twl4030_codec_get_mclk(void);
+int twl4030_audio_disable_resource(enum twl4030_audio_res id);
+int twl4030_audio_enable_resource(enum twl4030_audio_res id);
+unsigned int twl4030_audio_get_mclk(void);
 
 #endif /* End of __TWL4030_CODEC_H__ */
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h
new file mode 100644 (file)
index 0000000..4c806f6
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * MFD driver for twl6040
+ *
+ * Authors:     Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ *              Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright:   (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL6040_CODEC_H__
+#define __TWL6040_CODEC_H__
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+
+#define TWL6040_REG_ASICID             0x01
+#define TWL6040_REG_ASICREV            0x02
+#define TWL6040_REG_INTID              0x03
+#define TWL6040_REG_INTMR              0x04
+#define TWL6040_REG_NCPCTL             0x05
+#define TWL6040_REG_LDOCTL             0x06
+#define TWL6040_REG_HPPLLCTL           0x07
+#define TWL6040_REG_LPPLLCTL           0x08
+#define TWL6040_REG_LPPLLDIV           0x09
+#define TWL6040_REG_AMICBCTL           0x0A
+#define TWL6040_REG_DMICBCTL           0x0B
+#define TWL6040_REG_MICLCTL            0x0C
+#define TWL6040_REG_MICRCTL            0x0D
+#define TWL6040_REG_MICGAIN            0x0E
+#define TWL6040_REG_LINEGAIN           0x0F
+#define TWL6040_REG_HSLCTL             0x10
+#define TWL6040_REG_HSRCTL             0x11
+#define TWL6040_REG_HSGAIN             0x12
+#define TWL6040_REG_EARCTL             0x13
+#define TWL6040_REG_HFLCTL             0x14
+#define TWL6040_REG_HFLGAIN            0x15
+#define TWL6040_REG_HFRCTL             0x16
+#define TWL6040_REG_HFRGAIN            0x17
+#define TWL6040_REG_VIBCTLL            0x18
+#define TWL6040_REG_VIBDATL            0x19
+#define TWL6040_REG_VIBCTLR            0x1A
+#define TWL6040_REG_VIBDATR            0x1B
+#define TWL6040_REG_HKCTL1             0x1C
+#define TWL6040_REG_HKCTL2             0x1D
+#define TWL6040_REG_GPOCTL             0x1E
+#define TWL6040_REG_ALB                        0x1F
+#define TWL6040_REG_DLB                        0x20
+#define TWL6040_REG_TRIM1              0x28
+#define TWL6040_REG_TRIM2              0x29
+#define TWL6040_REG_TRIM3              0x2A
+#define TWL6040_REG_HSOTRIM            0x2B
+#define TWL6040_REG_HFOTRIM            0x2C
+#define TWL6040_REG_ACCCTL             0x2D
+#define TWL6040_REG_STATUS             0x2E
+
+#define TWL6040_CACHEREGNUM            (TWL6040_REG_STATUS + 1)
+
+#define TWL6040_VIOREGNUM              18
+#define TWL6040_VDDREGNUM              21
+
+/* INTID (0x03) fields */
+
+#define TWL6040_THINT                  0x01
+#define TWL6040_PLUGINT                        0x02
+#define TWL6040_UNPLUGINT              0x04
+#define TWL6040_HOOKINT                        0x08
+#define TWL6040_HFINT                  0x10
+#define TWL6040_VIBINT                 0x20
+#define TWL6040_READYINT               0x40
+
+/* INTMR (0x04) fields */
+
+#define TWL6040_THMSK                  0x01
+#define TWL6040_PLUGMSK                        0x02
+#define TWL6040_HOOKMSK                        0x08
+#define TWL6040_HFMSK                  0x10
+#define TWL6040_VIBMSK                 0x20
+#define TWL6040_READYMSK               0x40
+#define TWL6040_ALLINT_MSK             0x7B
+
+/* NCPCTL (0x05) fields */
+
+#define TWL6040_NCPENA                 0x01
+#define TWL6040_NCPOPEN                        0x40
+
+/* LDOCTL (0x06) fields */
+
+#define TWL6040_LSLDOENA               0x01
+#define TWL6040_HSLDOENA               0x04
+#define TWL6040_REFENA                 0x40
+#define TWL6040_OSCENA                 0x80
+
+/* HPPLLCTL (0x07) fields */
+
+#define TWL6040_HPLLENA                        0x01
+#define TWL6040_HPLLRST                        0x02
+#define TWL6040_HPLLBP                 0x04
+#define TWL6040_HPLLSQRENA             0x08
+#define TWL6040_MCLK_12000KHZ          (0 << 5)
+#define TWL6040_MCLK_19200KHZ          (1 << 5)
+#define TWL6040_MCLK_26000KHZ          (2 << 5)
+#define TWL6040_MCLK_38400KHZ          (3 << 5)
+#define TWL6040_MCLK_MSK               0x60
+
+/* LPPLLCTL (0x08) fields */
+
+#define TWL6040_LPLLENA                        0x01
+#define TWL6040_LPLLRST                        0x02
+#define TWL6040_LPLLSEL                        0x04
+#define TWL6040_LPLLFIN                        0x08
+#define TWL6040_HPLLSEL                        0x10
+
+/* HSLCTL (0x10) fields */
+
+#define TWL6040_HSDACMODEL             0x02
+#define TWL6040_HSDRVMODEL             0x08
+
+/* HSRCTL (0x11) fields */
+
+#define TWL6040_HSDACMODER             0x02
+#define TWL6040_HSDRVMODER             0x08
+
+/* VIBCTLL (0x18) fields */
+
+#define TWL6040_VIBENAL                        0x01
+#define TWL6040_VIBCTRLL               0x04
+#define TWL6040_VIBCTRLLP              0x08
+#define TWL6040_VIBCTRLLN              0x10
+
+/* VIBDATL (0x19) fields */
+
+#define TWL6040_VIBDAT_MAX             0x64
+
+/* VIBCTLR (0x1A) fields */
+
+#define TWL6040_VIBENAR                        0x01
+#define TWL6040_VIBCTRLR               0x04
+#define TWL6040_VIBCTRLRP              0x08
+#define TWL6040_VIBCTRLRN              0x10
+
+/* GPOCTL (0x1E) fields */
+
+#define TWL6040_GPO1                   0x01
+#define TWL6040_GPO2                   0x02
+#define TWL6040_GPO3                   0x03
+
+/* ACCCTL (0x2D) fields */
+
+#define TWL6040_I2CSEL                 0x01
+#define TWL6040_RESETSPLIT             0x04
+#define TWL6040_INTCLRMODE             0x08
+
+/* STATUS (0x2E) fields */
+
+#define TWL6040_PLUGCOMP               0x02
+#define TWL6040_VIBLOCDET              0x10
+#define TWL6040_VIBROCDET              0x20
+#define TWL6040_TSHUTDET                0x40
+
+#define TWL6040_CELLS                  2
+
+#define TWL6040_REV_ES1_0              0x00
+#define TWL6040_REV_ES1_1              0x01
+#define TWL6040_REV_ES1_2              0x02
+
+#define TWL6040_IRQ_TH                 0
+#define TWL6040_IRQ_PLUG               1
+#define TWL6040_IRQ_HOOK               2
+#define TWL6040_IRQ_HF                 3
+#define TWL6040_IRQ_VIB                        4
+#define TWL6040_IRQ_READY              5
+
+/* PLL selection */
+#define TWL6040_SYSCLK_SEL_LPPLL       0
+#define TWL6040_SYSCLK_SEL_HPPLL       1
+
+struct twl6040 {
+       struct device *dev;
+       struct mutex mutex;
+       struct mutex io_mutex;
+       struct mutex irq_mutex;
+       struct mfd_cell cells[TWL6040_CELLS];
+       struct completion ready;
+
+       int audpwron;
+       int power_count;
+       int rev;
+
+       int pll;
+       unsigned int sysclk;
+
+       unsigned int irq;
+       unsigned int irq_base;
+       u8 irq_masks_cur;
+       u8 irq_masks_cache;
+};
+
+int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg);
+int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg,
+                     u8 val);
+int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg,
+                    u8 mask);
+int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg,
+                      u8 mask);
+int twl6040_power(struct twl6040 *twl6040, int on);
+int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
+                   unsigned int freq_in, unsigned int freq_out);
+int twl6040_get_pll(struct twl6040 *twl6040);
+unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
+int twl6040_irq_init(struct twl6040 *twl6040);
+void twl6040_irq_exit(struct twl6040 *twl6040);
+
+#endif  /* End of __TWL6040_CODEC_H__ */
index 36a030f1d1f5ba5acd390186c338d53f2907bbca..379b2e3afd9805d2a3fb66c8e74f55c65c586b68 100644 (file)
@@ -250,10 +250,11 @@ config SND_SOC_TLV320DAC33
        tristate
 
 config SND_SOC_TWL4030
-       select TWL4030_CODEC
+       select MFD_TWL4030_AUDIO
        tristate
 
 config SND_SOC_TWL6040
+       select TWL6040_CORE
        tristate
 
 config SND_SOC_UDA134X
index bec788b12613add7ea8927762c23bb0572105b1a..71674bec9604fcceddf630ffaacfbf80895c0e0e 100644 (file)
@@ -36,7 +36,7 @@
 #include <sound/tlv.h>
 
 /* Register descriptions are here */
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
 
 /* Shadow register used by the audio driver */
 #define TWL4030_REG_SW_SHADOW          0x4A
@@ -251,9 +251,9 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
                return;
 
        if (enable)
-               mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER);
+               mode = twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
        else
-               mode = twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
+               mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
 
        if (mode >= 0) {
                twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode);
@@ -297,7 +297,7 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
 
 static void twl4030_init_chip(struct snd_soc_codec *codec)
 {
-       struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
+       struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 reg, byte;
        int i = 0;
@@ -375,13 +375,13 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
        if (enable) {
                twl4030->apll_enabled++;
                if (twl4030->apll_enabled == 1)
-                       status = twl4030_codec_enable_resource(
-                                                       TWL4030_CODEC_RES_APLL);
+                       status = twl4030_audio_enable_resource(
+                                                       TWL4030_AUDIO_RES_APLL);
        } else {
                twl4030->apll_enabled--;
                if (!twl4030->apll_enabled)
-                       status = twl4030_codec_disable_resource(
-                                                       TWL4030_CODEC_RES_APLL);
+                       status = twl4030_audio_disable_resource(
+                                                       TWL4030_AUDIO_RES_APLL);
        }
 
        if (status >= 0)
@@ -732,7 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
+       struct twl4030_codec_data *pdata = codec->dev->platform_data;
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -2260,7 +2260,7 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
        }
        snd_soc_codec_set_drvdata(codec, twl4030);
        /* Set the defaults, and power up the codec */
-       twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
+       twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
        codec->dapm.idle_bias_off = 1;
 
        twl4030_init_chip(codec);
@@ -2297,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
+       struct twl4030_codec_data *pdata = pdev->dev.platform_data;
 
        if (!pdata) {
                dev_err(&pdev->dev, "platform_data is missing\n");
index cd63bba623df712fc626735c706ee06252771dc5..443032b3b3296baca51be67e7660a3c3d937f2c3 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/i2c/twl.h>
+#include <linux/mfd/twl6040.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -77,14 +76,19 @@ struct twl6040_jack_data {
 
 /* codec private data */
 struct twl6040_data {
-       int audpwron;
-       int naudint;
+       int plug_irq;
        int codec_powered;
        int pll;
        int non_lp;
+       int pll_power_mode;
+       int hs_power_mode;
+       int hs_power_mode_locked;
+       unsigned int clk_in;
        unsigned int sysclk;
-       struct snd_pcm_hw_constraint_list *sysclk_constraints;
-       struct completion ready;
+       u16 hs_left_step;
+       u16 hs_right_step;
+       u16 hf_left_step;
+       u16 hf_right_step;
        struct twl6040_jack_data hs_jack;
        struct snd_soc_codec *codec;
        struct workqueue_struct *workqueue;
@@ -206,6 +210,32 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
        TWL6040_REG_DLB,
 };
 
+/* set of rates for each pll: low-power and high-performance */
+static unsigned int lp_rates[] = {
+       8000,
+       11250,
+       16000,
+       22500,
+       32000,
+       44100,
+       48000,
+       88200,
+       96000,
+};
+
+static unsigned int hp_rates[] = {
+       8000,
+       16000,
+       32000,
+       48000,
+       96000,
+};
+
+static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
+       { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
+       { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
+};
+
 /*
  * read twl6040 register cache
  */
@@ -239,12 +269,13 @@ static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
 static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
                        unsigned int reg)
 {
+       struct twl6040 *twl6040 = codec->control_data;
        u8 value;
 
        if (reg >= TWL6040_CACHEREGNUM)
                return -EIO;
 
-       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg);
+       value = twl6040_reg_read(twl6040, reg);
        twl6040_write_reg_cache(codec, reg, value);
 
        return value;
@@ -256,11 +287,13 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
 static int twl6040_write(struct snd_soc_codec *codec,
                        unsigned int reg, unsigned int value)
 {
+       struct twl6040 *twl6040 = codec->control_data;
+
        if (reg >= TWL6040_CACHEREGNUM)
                return -EIO;
 
        twl6040_write_reg_cache(codec, reg, value);
-       return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg);
+       return twl6040_reg_write(twl6040, reg, value);
 }
 
 static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
@@ -268,15 +301,21 @@ static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
        u8 *cache = codec->reg_cache;
        int reg, i;
 
-       /* allow registers to be accessed by i2c */
-       twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]);
-
        for (i = 0; i < TWL6040_VIOREGNUM; i++) {
                reg = twl6040_vio_reg[i];
-               /* skip read-only registers (ASICID, ASICREV, STATUS) */
+               /*
+                * skip read-only registers (ASICID, ASICREV, STATUS)
+                * and registers shared among MFD children
+                */
                switch (reg) {
                case TWL6040_REG_ASICID:
                case TWL6040_REG_ASICREV:
+               case TWL6040_REG_INTID:
+               case TWL6040_REG_INTMR:
+               case TWL6040_REG_NCPCTL:
+               case TWL6040_REG_LDOCTL:
+               case TWL6040_REG_GPOCTL:
+               case TWL6040_REG_ACCCTL:
                case TWL6040_REG_STATUS:
                        continue;
                default:
@@ -293,6 +332,20 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
 
        for (i = 0; i < TWL6040_VDDREGNUM; i++) {
                reg = twl6040_vdd_reg[i];
+               /* skip vibra and PLL registers */
+               switch (reg) {
+               case TWL6040_REG_VIBCTLL:
+               case TWL6040_REG_VIBDATL:
+               case TWL6040_REG_VIBCTLR:
+               case TWL6040_REG_VIBDATR:
+               case TWL6040_REG_HPPLLCTL:
+               case TWL6040_REG_LPPLLCTL:
+               case TWL6040_REG_LPPLLDIV:
+                       continue;
+               default:
+                       break;
+               }
+
                twl6040_write(codec, reg, cache[reg]);
        }
 }
@@ -317,7 +370,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
        if (headset->ramp == TWL6040_RAMP_UP) {
                /* ramp step up */
                if (val < headset->left_vol) {
-                       val += left_step;
+                       if (val + left_step > headset->left_vol)
+                               val = headset->left_vol;
+                       else
+                               val += left_step;
+
                        reg &= ~TWL6040_HSL_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HSGAIN,
                                        (reg | (~val & TWL6040_HSL_VOL_MASK)));
@@ -327,7 +384,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
        } else if (headset->ramp == TWL6040_RAMP_DOWN) {
                /* ramp step down */
                if (val > 0x0) {
-                       val -= left_step;
+                       if ((int)val - (int)left_step < 0)
+                               val = 0;
+                       else
+                               val -= left_step;
+
                        reg &= ~TWL6040_HSL_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
                                                (~val & TWL6040_HSL_VOL_MASK));
@@ -344,7 +405,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
        if (headset->ramp == TWL6040_RAMP_UP) {
                /* ramp step up */
                if (val < headset->right_vol) {
-                       val += right_step;
+                       if (val + right_step > headset->right_vol)
+                               val = headset->right_vol;
+                       else
+                               val += right_step;
+
                        reg &= ~TWL6040_HSR_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HSGAIN,
                                (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
@@ -354,7 +419,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
        } else if (headset->ramp == TWL6040_RAMP_DOWN) {
                /* ramp step down */
                if (val > 0x0) {
-                       val -= right_step;
+                       if ((int)val - (int)right_step < 0)
+                               val = 0;
+                       else
+                               val -= right_step;
+
                        reg &= ~TWL6040_HSR_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HSGAIN,
                                         reg | (~val << TWL6040_HSR_VOL_SHIFT));
@@ -385,7 +454,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
        if (handsfree->ramp == TWL6040_RAMP_UP) {
                /* ramp step up */
                if (val < handsfree->left_vol) {
-                       val += left_step;
+                       if (val + left_step > handsfree->left_vol)
+                               val = handsfree->left_vol;
+                       else
+                               val += left_step;
+
                        reg &= ~TWL6040_HF_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HFLGAIN,
                                                reg | (0x1D - val));
@@ -395,7 +468,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
        } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
                /* ramp step down */
                if (val > 0) {
-                       val -= left_step;
+                       if ((int)val - (int)left_step < 0)
+                               val = 0;
+                       else
+                               val -= left_step;
+
                        reg &= ~TWL6040_HF_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HFLGAIN,
                                                reg | (0x1D - val));
@@ -412,7 +489,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
        if (handsfree->ramp == TWL6040_RAMP_UP) {
                /* ramp step up */
                if (val < handsfree->right_vol) {
-                       val += right_step;
+                       if (val + right_step > handsfree->right_vol)
+                               val = handsfree->right_vol;
+                       else
+                               val += right_step;
+
                        reg &= ~TWL6040_HF_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HFRGAIN,
                                                reg | (0x1D - val));
@@ -422,7 +503,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
        } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
                /* ramp step down */
                if (val > 0) {
-                       val -= right_step;
+                       if ((int)val - (int)right_step < 0)
+                               val = 0;
+                       else
+                               val -= right_step;
+
                        reg &= ~TWL6040_HF_VOL_MASK;
                        twl6040_write(codec, TWL6040_REG_HFRGAIN,
                                                reg | (0x1D - val));
@@ -451,11 +536,9 @@ static void twl6040_pga_hs_work(struct work_struct *work)
 
        /* HS PGA volumes have 4 bits of resolution to ramp */
        for (i = 0; i <= 16; i++) {
-               headset_complete = 1;
-               if (headset->ramp != TWL6040_RAMP_NONE)
-                       headset_complete = twl6040_hs_ramp_step(codec,
-                                                       headset->left_step,
-                                                       headset->right_step);
+               headset_complete = twl6040_hs_ramp_step(codec,
+                                               headset->left_step,
+                                               headset->right_step);
 
                /* ramp finished ? */
                if (headset_complete)
@@ -496,11 +579,9 @@ static void twl6040_pga_hf_work(struct work_struct *work)
 
        /* HF PGA volumes have 5 bits of resolution to ramp */
        for (i = 0; i <= 32; i++) {
-               handsfree_complete = 1;
-               if (handsfree->ramp != TWL6040_RAMP_NONE)
-                       handsfree_complete = twl6040_hf_ramp_step(codec,
-                                                       handsfree->left_step,
-                                                       handsfree->right_step);
+               handsfree_complete = twl6040_hf_ramp_step(codec,
+                                               handsfree->left_step,
+                                               handsfree->right_step);
 
                /* ramp finished ? */
                if (handsfree_complete)
@@ -541,12 +622,16 @@ static int pga_event(struct snd_soc_dapm_widget *w,
                out = &priv->headset;
                work = &priv->hs_delayed_work;
                queue = priv->hs_workqueue;
+               out->left_step = priv->hs_left_step;
+               out->right_step = priv->hs_right_step;
                out->step_delay = 5;    /* 5 ms between volume ramp steps */
                break;
        case 4:
                out = &priv->handsfree;
                work = &priv->hf_delayed_work;
                queue = priv->hf_workqueue;
+               out->left_step = priv->hf_left_step;
+               out->right_step = priv->hf_right_step;
                out->step_delay = 5;    /* 5 ms between volume ramp steps */
                if (SND_SOC_DAPM_EVENT_ON(event))
                        priv->non_lp++;
@@ -579,8 +664,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
 
                if (!delayed_work_pending(work)) {
                        /* use volume ramp for power-down */
-                       out->left_step = 1;
-                       out->right_step = 1;
                        out->ramp = TWL6040_RAMP_DOWN;
                        INIT_COMPLETION(out->ramp_done);
 
@@ -596,88 +679,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-/* twl6040 codec manual power-up sequence */
-static void twl6040_power_up(struct snd_soc_codec *codec)
-{
-       u8 ncpctl, ldoctl, lppllctl, accctl;
-
-       ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
-       ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
-       lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
-       accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
-
-       /* enable reference system */
-       ldoctl |= TWL6040_REFENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       msleep(10);
-       /* enable internal oscillator */
-       ldoctl |= TWL6040_OSCENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(10);
-       /* enable high-side ldo */
-       ldoctl |= TWL6040_HSLDOENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(244);
-       /* enable negative charge pump */
-       ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
-       twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
-       udelay(488);
-       /* enable low-side ldo */
-       ldoctl |= TWL6040_LSLDOENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(244);
-       /* enable low-power pll */
-       lppllctl |= TWL6040_LPLLENA;
-       twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-       /* reset state machine */
-       accctl |= TWL6040_RESETSPLIT;
-       twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
-       mdelay(5);
-       accctl &= ~TWL6040_RESETSPLIT;
-       twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
-       /* disable internal oscillator */
-       ldoctl &= ~TWL6040_OSCENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-}
-
-/* twl6040 codec manual power-down sequence */
-static void twl6040_power_down(struct snd_soc_codec *codec)
-{
-       u8 ncpctl, ldoctl, lppllctl, accctl;
-
-       ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
-       ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
-       lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
-       accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
-
-       /* enable internal oscillator */
-       ldoctl |= TWL6040_OSCENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(10);
-       /* disable low-power pll */
-       lppllctl &= ~TWL6040_LPLLENA;
-       twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-       /* disable low-side ldo */
-       ldoctl &= ~TWL6040_LSLDOENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(244);
-       /* disable negative charge pump */
-       ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
-       twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
-       udelay(488);
-       /* disable high-side ldo */
-       ldoctl &= ~TWL6040_HSLDOENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       udelay(244);
-       /* disable internal oscillator */
-       ldoctl &= ~TWL6040_OSCENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       /* disable reference system */
-       ldoctl &= ~TWL6040_REFENA;
-       twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-       msleep(10);
-}
-
 /* set headset dac and driver power mode */
 static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 {
@@ -713,15 +714,26 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = w->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
 
-       if (SND_SOC_DAPM_EVENT_ON(event))
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
                priv->non_lp++;
-       else
+               if (!strcmp(w->name, "Earphone Driver")) {
+                       /* Earphone doesn't support low power mode */
+                       priv->hs_power_mode_locked = 1;
+                       ret = headset_power_mode(codec, 1);
+               }
+       } else {
                priv->non_lp--;
+               if (!strcmp(w->name, "Earphone Driver")) {
+                       priv->hs_power_mode_locked = 0;
+                       ret = headset_power_mode(codec, priv->hs_power_mode);
+               }
+       }
 
        msleep(1);
 
-       return 0;
+       return ret;
 }
 
 static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
@@ -766,33 +778,19 @@ static void twl6040_accessory_work(struct work_struct *work)
 }
 
 /* audio interrupt handler */
-static irqreturn_t twl6040_naudint_handler(int irq, void *data)
+static irqreturn_t twl6040_audio_handler(int irq, void *data)
 {
        struct snd_soc_codec *codec = data;
+       struct twl6040 *twl6040 = codec->control_data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        u8 intid;
 
-       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID);
-
-       if (intid & TWL6040_THINT)
-               dev_alert(codec->dev, "die temp over-limit detection\n");
+       intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
 
        if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
                queue_delayed_work(priv->workqueue, &priv->delayed_work,
                                                        msecs_to_jiffies(200));
 
-       if (intid & TWL6040_HOOKINT)
-               dev_info(codec->dev, "hook detection\n");
-
-       if (intid & TWL6040_HFINT)
-               dev_alert(codec->dev, "hf drivers over current detection\n");
-
-       if (intid & TWL6040_VIBINT)
-               dev_alert(codec->dev, "vib drivers over current detection\n");
-
-       if (intid & TWL6040_READYINT)
-               complete(&priv->ready);
-
        return IRQ_HANDLED;
 }
 
@@ -1040,6 +1038,73 @@ static const struct snd_kcontrol_new hfr_mux_controls =
 static const struct snd_kcontrol_new ep_driver_switch_controls =
        SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
 
+/* Headset power mode */
+static const char *twl6040_power_mode_texts[] = {
+       "Low-Power", "High-Perfomance",
+};
+
+static const struct soc_enum twl6040_power_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts),
+                       twl6040_power_mode_texts);
+
+static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
+
+       return 0;
+}
+
+static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int high_perf = ucontrol->value.enumerated.item[0];
+       int ret = 0;
+
+       if (!priv->hs_power_mode_locked)
+               ret = headset_power_mode(codec, high_perf);
+
+       if (!ret)
+               priv->hs_power_mode = high_perf;
+
+       return ret;
+}
+
+static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
+
+       return 0;
+}
+
+static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->pll_power_mode = ucontrol->value.enumerated.item[0];
+
+       return 0;
+}
+
+int twl6040_get_clk_id(struct snd_soc_codec *codec)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       return priv->pll_power_mode;
+}
+EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
+
 static const struct snd_kcontrol_new twl6040_snd_controls[] = {
        /* Capture gains */
        SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1058,6 +1123,13 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
                TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
        SOC_SINGLE_TLV("Earphone Playback Volume",
                TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
+
+       SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
+               twl6040_headset_power_get_enum,
+               twl6040_headset_power_put_enum),
+
+       SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum,
+               twl6040_pll_get_enum, twl6040_pll_put_enum),
 };
 
 static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1231,36 +1303,11 @@ static int twl6040_add_widgets(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int twl6040_power_up_completion(struct snd_soc_codec *codec,
-                                       int naudint)
-{
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       int time_left;
-       u8 intid;
-
-       time_left = wait_for_completion_timeout(&priv->ready,
-                               msecs_to_jiffies(144));
-
-       if (!time_left) {
-               twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid,
-                                                       TWL6040_REG_INTID);
-               if (!(intid & TWL6040_READYINT)) {
-                       dev_err(codec->dev, "timeout waiting for READYINT\n");
-                       return -ETIMEDOUT;
-               }
-       }
-
-       priv->codec_powered = 1;
-
-       return 0;
-}
-
 static int twl6040_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
+       struct twl6040 *twl6040 = codec->control_data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       int audpwron = priv->audpwron;
-       int naudint = priv->naudint;
        int ret;
 
        switch (level) {
@@ -1272,58 +1319,23 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
                if (priv->codec_powered)
                        break;
 
-               if (gpio_is_valid(audpwron)) {
-                       /* use AUDPWRON line */
-                       gpio_set_value(audpwron, 1);
+               ret = twl6040_power(twl6040, 1);
+               if (ret)
+                       return ret;
 
-                       /* wait for power-up completion */
-                       ret = twl6040_power_up_completion(codec, naudint);
-                       if (ret)
-                               return ret;
-
-                       /* sync registers updated during power-up sequence */
-                       twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
-                       twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
-                       twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL);
-               } else {
-                       /* use manual power-up sequence */
-                       twl6040_power_up(codec);
-                       priv->codec_powered = 1;
-               }
+               priv->codec_powered = 1;
 
                /* initialize vdd/vss registers with reg_cache */
                twl6040_init_vdd_regs(codec);
 
                /* Set external boost GPO */
                twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
-
-               /* Set initial minimal gain values */
-               twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF);
-               twl6040_write(codec, TWL6040_REG_EARCTL, 0x1E);
-               twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D);
-               twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D);
                break;
        case SND_SOC_BIAS_OFF:
                if (!priv->codec_powered)
                        break;
 
-               if (gpio_is_valid(audpwron)) {
-                       /* use AUDPWRON line */
-                       gpio_set_value(audpwron, 0);
-
-                       /* power-down sequence latency */
-                       udelay(500);
-
-                       /* sync registers updated during power-down sequence */
-                       twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
-                       twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
-                       twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL,
-                                               0x00);
-               } else {
-                       /* use manual power-down sequence */
-                       twl6040_power_down(codec);
-               }
-
+               twl6040_power(twl6040, 0);
                priv->codec_powered = 0;
                break;
        }
@@ -1333,27 +1345,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-/* set of rates for each pll: low-power and high-performance */
-
-static unsigned int lp_rates[] = {
-       88200,
-       96000,
-};
-
-static struct snd_pcm_hw_constraint_list lp_constraints = {
-       .count  = ARRAY_SIZE(lp_rates),
-       .list   = lp_rates,
-};
-
-static unsigned int hp_rates[] = {
-       96000,
-};
-
-static struct snd_pcm_hw_constraint_list hp_constraints = {
-       .count  = ARRAY_SIZE(hp_rates),
-       .list   = hp_rates,
-};
-
 static int twl6040_startup(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
@@ -1363,7 +1354,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
 
        snd_pcm_hw_constraint_list(substream->runtime, 0,
                                SNDRV_PCM_HW_PARAM_RATE,
-                               priv->sysclk_constraints);
+                               &sysclk_constraints[priv->pll_power_mode]);
 
        return 0;
 }
@@ -1375,22 +1366,27 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       u8 lppllctl;
        int rate;
 
-       /* nothing to do for high-perf pll, it supports only 48 kHz */
-       if (priv->pll == TWL6040_HPPLL_ID)
-               return 0;
-
-       lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
-
        rate = params_rate(params);
        switch (rate) {
        case 11250:
        case 22500:
        case 44100:
        case 88200:
-               lppllctl |= TWL6040_LPLLFIN;
+               /* These rates are not supported when HPPLL is in use */
+               if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
+                       dev_err(codec->dev, "HPPLL does not support rate %d\n",
+                               rate);
+                       return -EINVAL;
+               }
+               /* Capture is not supported with 17.64MHz sysclk */
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       dev_err(codec->dev,
+                               "capture mode is not supported at %dHz\n",
+                               rate);
+                       return -EINVAL;
+               }
                priv->sysclk = 17640000;
                break;
        case 8000:
@@ -1398,7 +1394,6 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
        case 32000:
        case 48000:
        case 96000:
-               lppllctl &= ~TWL6040_LPLLFIN;
                priv->sysclk = 19200000;
                break;
        default:
@@ -1406,8 +1401,6 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-
        return 0;
 }
 
@@ -1416,7 +1409,9 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
+       struct twl6040 *twl6040 = codec->control_data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
        if (!priv->sysclk) {
                dev_err(codec->dev,
@@ -1424,24 +1419,19 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /*
-        * capture is not supported at 17.64 MHz,
-        * it's reserved for headset low-power playback scenario
-        */
-       if ((priv->sysclk == 17640000) &&
-                       substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               dev_err(codec->dev,
-                       "capture mode is not supported at %dHz\n",
-                       priv->sysclk);
-               return -EINVAL;
-       }
-
        if ((priv->sysclk == 17640000) && priv->non_lp) {
                        dev_err(codec->dev,
                                "some enabled paths aren't supported at %dHz\n",
                                priv->sysclk);
                        return -EPERM;
        }
+
+       ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
+       if (ret) {
+               dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
+               return -EPERM;
+       }
+
        return 0;
 }
 
@@ -1450,99 +1440,12 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       u8 hppllctl, lppllctl;
-
-       hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL);
-       lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
 
        switch (clk_id) {
        case TWL6040_SYSCLK_SEL_LPPLL:
-               switch (freq) {
-               case 32768:
-                       /* headset dac and driver must be in low-power mode */
-                       headset_power_mode(codec, 0);
-
-                       /* clk32k input requires low-power pll */
-                       lppllctl |= TWL6040_LPLLENA;
-                       twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-                       mdelay(5);
-                       lppllctl &= ~TWL6040_HPLLSEL;
-                       twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-                       hppllctl &= ~TWL6040_HPLLENA;
-                       twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
-                       break;
-               default:
-                       dev_err(codec->dev, "unknown mclk freq %d\n", freq);
-                       return -EINVAL;
-               }
-
-               /* lppll divider */
-               switch (priv->sysclk) {
-               case 17640000:
-                       lppllctl |= TWL6040_LPLLFIN;
-                       break;
-               case 19200000:
-                       lppllctl &= ~TWL6040_LPLLFIN;
-                       break;
-               default:
-                       /* sysclk not yet configured */
-                       lppllctl &= ~TWL6040_LPLLFIN;
-                       priv->sysclk = 19200000;
-                       break;
-               }
-
-               twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-
-               priv->pll = TWL6040_LPPLL_ID;
-               priv->sysclk_constraints = &lp_constraints;
-               break;
        case TWL6040_SYSCLK_SEL_HPPLL:
-               hppllctl &= ~TWL6040_MCLK_MSK;
-
-               switch (freq) {
-               case 12000000:
-                       /* mclk input, pll enabled */
-                       hppllctl |= TWL6040_MCLK_12000KHZ |
-                                   TWL6040_HPLLSQRBP |
-                                   TWL6040_HPLLENA;
-                       break;
-               case 19200000:
-                       /* mclk input, pll disabled */
-                       hppllctl |= TWL6040_MCLK_19200KHZ |
-                                   TWL6040_HPLLSQRENA |
-                                   TWL6040_HPLLBP;
-                       break;
-               case 26000000:
-                       /* mclk input, pll enabled */
-                       hppllctl |= TWL6040_MCLK_26000KHZ |
-                                   TWL6040_HPLLSQRBP |
-                                   TWL6040_HPLLENA;
-                       break;
-               case 38400000:
-                       /* clk slicer, pll disabled */
-                       hppllctl |= TWL6040_MCLK_38400KHZ |
-                                   TWL6040_HPLLSQRENA |
-                                   TWL6040_HPLLBP;
-                       break;
-               default:
-                       dev_err(codec->dev, "unknown mclk freq %d\n", freq);
-                       return -EINVAL;
-               }
-
-               /* headset dac and driver must be in high-performance mode */
-               headset_power_mode(codec, 1);
-
-               twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
-               udelay(500);
-               lppllctl |= TWL6040_HPLLSEL;
-               twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-               lppllctl &= ~TWL6040_LPLLENA;
-               twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
-
-               /* high-performance pll can provide only 19.2 MHz */
-               priv->pll = TWL6040_HPPLL_ID;
-               priv->sysclk = 19200000;
-               priv->sysclk_constraints = &hp_constraints;
+               priv->pll = clk_id;
+               priv->clk_in = freq;
                break;
        default:
                dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
@@ -1559,15 +1462,27 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
        .set_sysclk     = twl6040_set_dai_sysclk,
 };
 
-static struct snd_soc_dai_driver twl6040_dai = {
+static struct snd_soc_dai_driver twl6040_dai[] = {
+{
        .name = "twl6040-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
-               .channels_max = 4,
+               .channels_max = 2,
+               .rates = TWL6040_RATES,
+               .formats = TWL6040_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
                .rates = TWL6040_RATES,
                .formats = TWL6040_FORMATS,
        },
+       .ops = &twl6040_dai_ops,
+},
+{
+       .name = "twl6040-ul",
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -1576,6 +1491,40 @@ static struct snd_soc_dai_driver twl6040_dai = {
                .formats = TWL6040_FORMATS,
        },
        .ops = &twl6040_dai_ops,
+},
+{
+       .name = "twl6040-dl1",
+       .playback = {
+               .stream_name = "Headset Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = TWL6040_RATES,
+               .formats = TWL6040_FORMATS,
+       },
+       .ops = &twl6040_dai_ops,
+},
+{
+       .name = "twl6040-dl2",
+       .playback = {
+               .stream_name = "Handsfree Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = TWL6040_RATES,
+               .formats = TWL6040_FORMATS,
+       },
+       .ops = &twl6040_dai_ops,
+},
+{
+       .name = "twl6040-vib",
+       .playback = {
+               .stream_name = "Vibra Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .formats = TWL6040_FORMATS,
+       },
+       .ops = &twl6040_dai_ops,
+},
 };
 
 #ifdef CONFIG_PM
@@ -1600,11 +1549,11 @@ static int twl6040_resume(struct snd_soc_codec *codec)
 
 static int twl6040_probe(struct snd_soc_codec *codec)
 {
-       struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
        struct twl6040_data *priv;
-       int audpwron, naudint;
+       struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
+       struct platform_device *pdev = container_of(codec->dev,
+                                                  struct platform_device, dev);
        int ret = 0;
-       u8 icrev, intmr = TWL6040_ALLINT_MSK;
 
        priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
        if (priv == NULL)
@@ -1612,23 +1561,32 @@ static int twl6040_probe(struct snd_soc_codec *codec)
        snd_soc_codec_set_drvdata(codec, priv);
 
        priv->codec = codec;
+       codec->control_data = dev_get_drvdata(codec->dev->parent);
 
-       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV);
+       if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
+               priv->hs_left_step = pdata->hs_left_step;
+               priv->hs_right_step = pdata->hs_right_step;
+       } else {
+               priv->hs_left_step = 1;
+               priv->hs_right_step = 1;
+       }
 
-       if (twl_codec && (icrev > 0))
-               audpwron = twl_codec->audpwron_gpio;
-       else
-               audpwron = -EINVAL;
+       if (pdata && pdata->hf_left_step && pdata->hf_right_step) {
+               priv->hf_left_step = pdata->hf_left_step;
+               priv->hf_right_step = pdata->hf_right_step;
+       } else {
+               priv->hf_left_step = 1;
+               priv->hf_right_step = 1;
+       }
 
-       if (twl_codec)
-               naudint = twl_codec->naudint_irq;
-       else
-               naudint = 0;
+       priv->plug_irq = platform_get_irq(pdev, 0);
+       if (priv->plug_irq < 0) {
+               dev_err(codec->dev, "invalid irq\n");
+               ret = -EINVAL;
+               goto work_err;
+       }
 
-       priv->audpwron = audpwron;
-       priv->naudint = naudint;
        priv->workqueue = create_singlethread_workqueue("twl6040-codec");
-
        if (!priv->workqueue) {
                ret = -ENOMEM;
                goto work_err;
@@ -1638,56 +1596,33 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 
        mutex_init(&priv->mutex);
 
-       init_completion(&priv->ready);
        init_completion(&priv->headset.ramp_done);
        init_completion(&priv->handsfree.ramp_done);
 
-       if (gpio_is_valid(audpwron)) {
-               ret = gpio_request(audpwron, "audpwron");
-               if (ret)
-                       goto gpio1_err;
-
-               ret = gpio_direction_output(audpwron, 0);
-               if (ret)
-                       goto gpio2_err;
-
-               priv->codec_powered = 0;
-
-               /* enable only codec ready interrupt */
-               intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK);
-
-               /* reset interrupt status to allow correct power up sequence */
-               twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
-       }
-       twl6040_write(codec, TWL6040_REG_INTMR, intmr);
-
-       if (naudint) {
-               /* audio interrupt */
-               ret = request_threaded_irq(naudint, NULL,
-                               twl6040_naudint_handler,
-                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                               "twl6040_codec", codec);
-               if (ret)
-                       goto gpio2_err;
-       }
-
-       /* init vio registers */
-       twl6040_init_vio_regs(codec);
-
        priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
        if (priv->hf_workqueue == NULL) {
                ret = -ENOMEM;
-               goto irq_err;
+               goto hfwq_err;
        }
        priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
        if (priv->hs_workqueue == NULL) {
                ret = -ENOMEM;
-               goto wq_err;
+               goto hswq_err;
        }
 
        INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
        INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
 
+       ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
+                                  0, "twl6040_irq_plug", codec);
+       if (ret) {
+               dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
+               goto plugirq_err;
+       }
+
+       /* init vio registers */
+       twl6040_init_vio_regs(codec);
+
        /* power on device */
        ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        if (ret)
@@ -1700,16 +1635,12 @@ static int twl6040_probe(struct snd_soc_codec *codec)
        return 0;
 
 bias_err:
+       free_irq(priv->plug_irq, codec);
+plugirq_err:
        destroy_workqueue(priv->hs_workqueue);
-wq_err:
+hswq_err:
        destroy_workqueue(priv->hf_workqueue);
-irq_err:
-       if (naudint)
-               free_irq(naudint, codec);
-gpio2_err:
-       if (gpio_is_valid(audpwron))
-               gpio_free(audpwron);
-gpio1_err:
+hfwq_err:
        destroy_workqueue(priv->workqueue);
 work_err:
        kfree(priv);
@@ -1719,17 +1650,9 @@ work_err:
 static int twl6040_remove(struct snd_soc_codec *codec)
 {
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       int audpwron = priv->audpwron;
-       int naudint = priv->naudint;
 
        twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       if (gpio_is_valid(audpwron))
-               gpio_free(audpwron);
-
-       if (naudint)
-               free_irq(naudint, codec);
-
+       free_irq(priv->plug_irq, codec);
        destroy_workqueue(priv->workqueue);
        destroy_workqueue(priv->hf_workqueue);
        destroy_workqueue(priv->hs_workqueue);
@@ -1753,8 +1676,8 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
 
 static int __devinit twl6040_codec_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_codec(&pdev->dev,
-                       &soc_codec_dev_twl6040, &twl6040_dai, 1);
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040,
+                                     twl6040_dai, ARRAY_SIZE(twl6040_dai));
 }
 
 static int __devexit twl6040_codec_remove(struct platform_device *pdev)
index 23aeed0963e69dbdcf72387bffb9526f270c299b..d8de67869dd9340c31f040a755d8dae1d8591278 100644 (file)
 #ifndef __TWL6040_H__
 #define __TWL6040_H__
 
-#define TWL6040_REG_ASICID             0x01
-#define TWL6040_REG_ASICREV            0x02
-#define TWL6040_REG_INTID              0x03
-#define TWL6040_REG_INTMR              0x04
-#define TWL6040_REG_NCPCTL             0x05
-#define TWL6040_REG_LDOCTL             0x06
-#define TWL6040_REG_HPPLLCTL           0x07
-#define TWL6040_REG_LPPLLCTL           0x08
-#define TWL6040_REG_LPPLLDIV           0x09
-#define TWL6040_REG_AMICBCTL           0x0A
-#define TWL6040_REG_DMICBCTL           0x0B
-#define TWL6040_REG_MICLCTL            0x0C
-#define TWL6040_REG_MICRCTL            0x0D
-#define TWL6040_REG_MICGAIN            0x0E
-#define TWL6040_REG_LINEGAIN           0x0F
-#define TWL6040_REG_HSLCTL             0x10
-#define TWL6040_REG_HSRCTL             0x11
-#define TWL6040_REG_HSGAIN             0x12
-#define TWL6040_REG_EARCTL             0x13
-#define TWL6040_REG_HFLCTL             0x14
-#define TWL6040_REG_HFLGAIN            0x15
-#define TWL6040_REG_HFRCTL             0x16
-#define TWL6040_REG_HFRGAIN            0x17
-#define TWL6040_REG_VIBCTLL            0x18
-#define TWL6040_REG_VIBDATL            0x19
-#define TWL6040_REG_VIBCTLR            0x1A
-#define TWL6040_REG_VIBDATR            0x1B
-#define TWL6040_REG_HKCTL1             0x1C
-#define TWL6040_REG_HKCTL2             0x1D
-#define TWL6040_REG_GPOCTL             0x1E
-#define TWL6040_REG_ALB                        0x1F
-#define TWL6040_REG_DLB                        0x20
-#define TWL6040_REG_TRIM1              0x28
-#define TWL6040_REG_TRIM2              0x29
-#define TWL6040_REG_TRIM3              0x2A
-#define TWL6040_REG_HSOTRIM            0x2B
-#define TWL6040_REG_HFOTRIM            0x2C
-#define TWL6040_REG_ACCCTL             0x2D
-#define TWL6040_REG_STATUS             0x2E
-
-#define TWL6040_CACHEREGNUM            (TWL6040_REG_STATUS + 1)
-
-#define TWL6040_VIOREGNUM              18
-#define TWL6040_VDDREGNUM              21
-
-/* INTID (0x03) fields */
-
-#define TWL6040_THINT                  0x01
-#define TWL6040_PLUGINT                        0x02
-#define TWL6040_UNPLUGINT              0x04
-#define TWL6040_HOOKINT                        0x08
-#define TWL6040_HFINT                  0x10
-#define TWL6040_VIBINT                 0x20
-#define TWL6040_READYINT               0x40
-
-/* INTMR (0x04) fields */
-
-#define TWL6040_PLUGMSK                        0x02
-#define TWL6040_READYMSK               0x40
-#define TWL6040_ALLINT_MSK             0x7B
-
-/* NCPCTL (0x05) fields */
-
-#define TWL6040_NCPENA                 0x01
-#define TWL6040_NCPOPEN                        0x40
-
-/* LDOCTL (0x06) fields */
-
-#define TWL6040_LSLDOENA               0x01
-#define TWL6040_HSLDOENA               0x04
-#define TWL6040_REFENA                 0x40
-#define TWL6040_OSCENA                 0x80
-
-/* HPPLLCTL (0x07) fields */
-
-#define TWL6040_HPLLENA                        0x01
-#define TWL6040_HPLLRST                        0x02
-#define TWL6040_HPLLBP                 0x04
-#define TWL6040_HPLLSQRENA             0x08
-#define TWL6040_HPLLSQRBP              0x10
-#define TWL6040_MCLK_12000KHZ          (0 << 5)
-#define TWL6040_MCLK_19200KHZ          (1 << 5)
-#define TWL6040_MCLK_26000KHZ          (2 << 5)
-#define TWL6040_MCLK_38400KHZ          (3 << 5)
-#define TWL6040_MCLK_MSK               0x60
-
-/* LPPLLCTL (0x08) fields */
-
-#define TWL6040_LPLLENA                        0x01
-#define TWL6040_LPLLRST                        0x02
-#define TWL6040_LPLLSEL                        0x04
-#define TWL6040_LPLLFIN                        0x08
-#define TWL6040_HPLLSEL                        0x10
-
-/* HSLCTL (0x10) fields */
-
-#define TWL6040_HSDACMODEL             0x02
-#define TWL6040_HSDRVMODEL             0x08
-
-/* HSRCTL (0x11) fields */
-
-#define TWL6040_HSDACMODER             0x02
-#define TWL6040_HSDRVMODER             0x08
-
-/* ACCCTL (0x2D) fields */
-
-#define TWL6040_RESETSPLIT             0x04
-
-#define TWL6040_SYSCLK_SEL_LPPLL       1
-#define TWL6040_SYSCLK_SEL_HPPLL       2
-
-#define TWL6040_HPPLL_ID               1
-#define TWL6040_LPPLL_ID               2
-
-/* STATUS (0x2E) fields */
-
-#define TWL6040_PLUGCOMP               0x02
-
 void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
                            struct snd_soc_jack *jack, int report);
+int twl6040_get_clk_id(struct snd_soc_codec *codec);
 
 #endif /* End of __TWL6040_H__ */
index 3f72d17d1ef02a037f79f566034f37edc34ece75..9f6a758029d16a63cbcd9b8930f64e2c9baceaef 100644 (file)
@@ -36,7 +36,7 @@
 #include <plat/mcbsp.h>
 
 /* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
index 189e039006376399ce61213a5de28af34c014388..b80efb02bfcae81ea365fce6c9f0be93a63dde28 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -34,8 +36,6 @@
 #include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
-static int twl6040_power_mode;
-
 static int sdp4430_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -44,13 +44,13 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
        int clk_id, freq;
        int ret;
 
-       if (twl6040_power_mode) {
-               clk_id = TWL6040_SYSCLK_SEL_HPPLL;
+       clk_id = twl6040_get_clk_id(rtd->codec);
+       if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
                freq = 38400000;
-       } else {
-               clk_id = TWL6040_SYSCLK_SEL_LPPLL;
+       else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
                freq = 32768;
-       }
+       else
+               return -EINVAL;
 
        /* set the codec mclk */
        ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
@@ -81,35 +81,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
        },
 };
 
-static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = twl6040_power_mode;
-       return 0;
-}
-
-static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       if (twl6040_power_mode == ucontrol->value.integer.value[0])
-               return 0;
-
-       twl6040_power_mode = ucontrol->value.integer.value[0];
-
-       return 1;
-}
-
-static const char *power_texts[] = {"Low-Power", "High-Performance"};
-
-static const struct soc_enum sdp4430_enum[] = {
-       SOC_ENUM_SINGLE_EXT(2, power_texts),
-};
-
-static const struct snd_kcontrol_new sdp4430_controls[] = {
-       SOC_ENUM_EXT("TWL6040 Power Mode", sdp4430_enum[0],
-               sdp4430_get_power_mode, sdp4430_set_power_mode),
-};
-
 /* SDP4430 machine DAPM */
 static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Ext Mic", NULL),
@@ -152,12 +123,6 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       /* Add SDP4430 specific controls */
-       ret = snd_soc_add_controls(codec, sdp4430_controls,
-                               ARRAY_SIZE(sdp4430_controls));
-       if (ret)
-               return ret;
-
        /* Add SDP4430 specific widgets */
        ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
                                ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
@@ -237,9 +202,6 @@ static int __init sdp4430_soc_init(void)
        if (ret)
                goto err;
 
-       /* Codec starts in HP mode */
-       twl6040_power_mode = 1;
-
        return 0;
 
 err:
index 01709940a43cde7abc81b8d06967ef4b85d78f28..9a2666ffc16c9b71b40ddf54cfc3464d217a1f62 100644 (file)
@@ -32,7 +32,7 @@
 #include <plat/mcbsp.h>
 
 /* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"