Browse Source

Merge branch 'next/devel2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc

* '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
  ...
Linus Torvalds 14 năm trước cách đây
mục cha
commit
b0189cd087
51 tập tin đã thay đổi với 3481 bổ sung1307 xóa
  1. 55 0
      arch/arm/mach-omap2/board-4430sdp.c
  2. 3 3
      arch/arm/mach-omap2/board-rx51-peripherals.c
  3. 5 5
      arch/arm/mach-omap2/board-zoom-peripherals.c
  4. 24 3
      arch/arm/mach-omap2/clock.c
  5. 3 0
      arch/arm/mach-omap2/clock.h
  6. 11 11
      arch/arm/mach-omap2/clock2420_data.c
  7. 16 16
      arch/arm/mach-omap2/clock2430_data.c
  8. 22 22
      arch/arm/mach-omap2/clock3xxx_data.c
  9. 172 43
      arch/arm/mach-omap2/clock44xx_data.c
  10. 169 41
      arch/arm/mach-omap2/clockdomain.c
  11. 11 0
      arch/arm/mach-omap2/clockdomain.h
  12. 4 2
      arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
  13. 4 9
      arch/arm/mach-omap2/clockdomain44xx.c
  14. 1 1
      arch/arm/mach-omap2/clockdomains44xx_data.c
  15. 1 7
      arch/arm/mach-omap2/cm44xx.h
  16. 133 17
      arch/arm/mach-omap2/cminst44xx.c
  17. 8 2
      arch/arm/mach-omap2/cminst44xx.h
  18. 204 30
      arch/arm/mach-omap2/omap_hwmod.c
  19. 261 57
      arch/arm/mach-omap2/omap_hwmod_44xx_data.c
  20. 3 1
      arch/arm/mach-omap2/pm.c
  21. 1 1
      arch/arm/mach-omap2/prcm.c
  22. 1 144
      arch/arm/mach-omap2/prm44xx.c
  23. 0 10
      arch/arm/mach-omap2/prm44xx.h
  24. 111 1
      arch/arm/mach-omap2/prminst44xx.c
  25. 10 2
      arch/arm/mach-omap2/prminst44xx.h
  26. 5 5
      arch/arm/mach-omap2/twl-common.c
  27. 39 0
      arch/arm/plat-omap/clock.c
  28. 10 2
      arch/arm/plat-omap/include/plat/irqs.h
  29. 12 2
      arch/arm/plat-omap/include/plat/omap_hwmod.h
  30. 50 35
      arch/arm/plat-omap/omap_device.c
  31. 12 1
      drivers/input/misc/Kconfig
  32. 1 0
      drivers/input/misc/Makefile
  33. 6 6
      drivers/input/misc/twl4030-vibra.c
  34. 423 0
      drivers/input/misc/twl6040-vibra.c
  35. 7 1
      drivers/mfd/Kconfig
  36. 2 1
      drivers/mfd/Makefile
  37. 6 7
      drivers/mfd/twl-core.c
  38. 277 0
      drivers/mfd/twl4030-audio.c
  39. 0 277
      drivers/mfd/twl4030-codec.c
  40. 620 0
      drivers/mfd/twl6040-core.c
  41. 191 0
      drivers/mfd/twl6040-irq.c
  42. 19 6
      include/linux/i2c/twl.h
  43. 8 8
      include/linux/mfd/twl4030-audio.h
  44. 228 0
      include/linux/mfd/twl6040.h
  45. 2 1
      sound/soc/codecs/Kconfig
  46. 11 11
      sound/soc/codecs/twl4030.c
  47. 309 351
      sound/soc/codecs/twl6040.c
  48. 1 118
      sound/soc/codecs/twl6040.h
  49. 1 1
      sound/soc/omap/sdp3430.c
  50. 7 45
      sound/soc/omap/sdp4430.c
  51. 1 1
      sound/soc/omap/zoom2.c

+ 55 - 0
arch/arm/mach-omap2/board-4430sdp.c

@@ -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,

+ 3 - 3
arch/arm/mach-omap2/board-rx51-peripherals.c

@@ -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,

+ 5 - 5
arch/arm/mach-omap2/board-zoom-peripherals.c

@@ -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);

+ 24 - 3
arch/arm/mach-omap2/clock.c

@@ -37,6 +37,14 @@
 
 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)

+ 3 - 0
arch/arm/mach-omap2/clock.h

@@ -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,

+ 11 - 11
arch/arm/mach-omap2/clock2420_data.c

@@ -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),

+ 16 - 16
arch/arm/mach-omap2/clock2430_data.c

@@ -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),

+ 22 - 22
arch/arm/mach-omap2/clock3xxx_data.c

@@ -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),

+ 172 - 43
arch/arm/mach-omap2/clock44xx_data.c

@@ -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++)

+ 169 - 41
arch/arm/mach-omap2/clockdomain.c

@@ -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);
 }
 

+ 11 - 0
arch/arm/mach-omap2/clockdomain.h

@@ -17,9 +17,11 @@
 #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);

+ 4 - 2
arch/arm/mach-omap2/clockdomain2xxx_3xxx.c

@@ -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;

+ 4 - 9
arch/arm/mach-omap2/clockdomain44xx.c

@@ -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;
 }

+ 1 - 1
arch/arm/mach-omap2/clockdomains44xx_data.c

@@ -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,

+ 1 - 7
arch/arm/mach-omap2/cm44xx.h

@@ -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
@@ -23,10 +23,4 @@
 #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

+ 133 - 17
arch/arm/mach-omap2/cminst44xx.c

@@ -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
@@ -32,6 +33,22 @@
 #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);
+}

+ 8 - 2
arch/arm/mach-omap2/cminst44xx.h

@@ -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

+ 204 - 30
arch/arm/mach-omap2/omap_hwmod.c

@@ -146,9 +146,10 @@
 #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? */
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 261 - 57
arch/arm/mach-omap2/omap_hwmod_44xx_data.c


+ 3 - 1
arch/arm/mach-omap2/pm.c

@@ -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]);

+ 1 - 1
arch/arm/mach-omap2/prcm.c

@@ -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);
 	}

+ 1 - 144
arch/arm/mach-omap2/prm44xx.c

@@ -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
@@ -24,12 +24,6 @@
 #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);
-}

+ 0 - 10
arch/arm/mach-omap2/prm44xx.h

@@ -750,16 +750,6 @@
 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
 

+ 111 - 1
arch/arm/mach-omap2/prminst44xx.c

@@ -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);
+}

+ 10 - 2
arch/arm/mach-omap2/prminst44xx.h

@@ -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
@@ -18,8 +19,15 @@
 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

+ 5 - 5
arch/arm/mach-omap2/twl-common.c

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

+ 39 - 0
arch/arm/plat-omap/clock.c

@@ -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);

+ 10 - 2
arch/arm/plat-omap/include/plat/irqs.h

@@ -407,11 +407,19 @@
 #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 */

+ 12 - 2
arch/arm/plat-omap/include/plat/omap_hwmod.h

@@ -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 */

+ 50 - 35
arch/arm/plat-omap/omap_device.c

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

+ 12 - 1
drivers/input/misc/Kconfig

@@ -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

+ 1 - 0
drivers/input/misc/Makefile

@@ -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

+ 6 - 6
drivers/input/misc/twl4030-vibra.c

@@ -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;
 

+ 423 - 0
drivers/input/misc/twl6040-vibra.c

@@ -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>");

+ 7 - 1
drivers/mfd/Kconfig

@@ -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

+ 2 - 1
drivers/mfd/Makefile

@@ -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
 

+ 6 - 7
drivers/mfd/twl-core.c

@@ -110,7 +110,7 @@
 #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);

+ 277 - 0
drivers/mfd/twl4030-audio.c

@@ -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");

+ 0 - 277
drivers/mfd/twl4030-codec.c

@@ -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");
-

+ 620 - 0
drivers/mfd/twl6040-core.c

@@ -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");

+ 191 - 0
drivers/mfd/twl6040-irq.c

@@ -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);

+ 19 - 6
include/linux/i2c/twl.h

@@ -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;

+ 8 - 8
include/linux/mfd/twl4030-codec.h → include/linux/mfd/twl4030-audio.h

@@ -1,5 +1,5 @@
 /*
- * MFD driver for twl4030 codec submodule
+ * MFD driver for twl4030 audio submodule
  *
  * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
@@ -259,14 +259,14 @@
 #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__ */

+ 228 - 0
include/linux/mfd/twl6040.h

@@ -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__ */

+ 2 - 1
sound/soc/codecs/Kconfig

@@ -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

+ 11 - 11
sound/soc/codecs/twl4030.c

@@ -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");

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 309 - 351
sound/soc/codecs/twl6040.c


+ 1 - 118
sound/soc/codecs/twl6040.h

@@ -22,125 +22,8 @@
 #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__ */

+ 1 - 1
sound/soc/omap/sdp3430.c

@@ -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"

+ 7 - 45
sound/soc/omap/sdp4430.c

@@ -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:

+ 1 - 1
sound/soc/omap/zoom2.c

@@ -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"

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác