From f19b2823f82499c60ec15d5fe8783193d77e3043 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Wed, 27 Apr 2011 02:14:07 -0500 Subject: mfd: twl6040: Add initial support TWL6040 IC provides analog high-end audio codec functions for handset applications. It contains several audio analog inputs and outputs as well as vibrator support. It's connected to the host processor via PDM interface for audio data communication. The audio modules are controlled by internal registers that can be accessed by I2C and PDM interface. TWL6040 MFD will be registered as a child of TWL-CORE, and will have two children of its own: twl6040-codec and twl6040-vibra. This driver is based on TWL4030 and WM8350 MFD drivers. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Acked-by: Samuel Ortiz --- arch/arm/plat-omap/include/plat/irqs.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index c88432005665..926d25c780f3 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/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 */ -- cgit v1.2.3 From bf1e0776cf5e4ef2622de3a4b63f84175b5b48ab Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:54:12 -0600 Subject: OMAP: omap_device: Create clkdev entry for hwmod main_clk Extend the existing function to create clkdev for every optional clocks to add a well one "fck" alias for the main_clk of the omap_hwmod. It will allow to remove these static clkdev entries from the clockXXX_data.c file. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Kevin Hilman Cc: Todd Poynor [paul@pwsan.com: remove all of the "fck" role clkdev aliases from the clock data files; fixed error message] Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/omap_device.c | 85 +++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 35 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index c8b9cd1716ba..be45147651cb 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/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 - * 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 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(, ). + * 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) -- cgit v1.2.3 From a5322c6f3a3b0a81347c57de2f3a86b851b49bcf Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:29 -0600 Subject: OMAP4: hwmod data: Add clock domain attribute In OMAP PRCM terminology, the clock domain is defined as a group of IPs that share some clocks and most of the time an interface clock. Every IP does belong to a clockdomain. For the moment the clock domain attribute is affected to a clock node. The issue with that approach, is that a clock might or not belong to a clock domain. Moreover during module transition, it is up to a module to handle properly the clock domain state and not to a clock node. Create a clkdm_name attribute to provide this information per hwmod. Populate this attribute for every OMAP4 hwmod entries. Future cleanup series with remove that information from the OMAP4 clock when it is relevant. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak [paul@pwsan.com: fix the mpuss_clkdm name] Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index fafdfe3c8d4e..21d392233ed0 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -515,6 +515,7 @@ struct omap_hwmod { const char *main_clk; struct clk *_clk; struct omap_hwmod_opt_clk *opt_clks; + char *clkdm_name; char *vdd_name; struct voltagedomain *voltdm; struct omap_hwmod_ocp_if **masters; /* connect to *_IA */ -- cgit v1.2.3 From 6ae769973adf1325115d0dfe3fec17e26cbacd81 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:30 -0600 Subject: OMAP2+: hwmod: Init clkdm field at boot time At boot time, lookup the clkdm_name to get the clkdm structure pointer for further usage. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 21d392233ed0..3306bdfb79a1 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -516,6 +516,7 @@ struct omap_hwmod { 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 */ -- cgit v1.2.3 From d0f0631ddc61026dca71b5b679803000d70fde50 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:30 -0600 Subject: OMAP4: hwmod: Replace CLKCTRL absolute address with offset macros The CLKCTRL register was accessed using an absolute address. The usage of hardcoded macros to calculate virtual address from physical one should be avoided as much as possible. The usage of a offset will allow future improvement like migration from the current architecture code toward a module driver. Update cm_xxx accessor, move definition to the proper header file and update copyrights. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak Cc: Todd Poynor [paul@pwsan.com: renamed 'omap4_cm_' fns to 'omap4_cminst_'; removed empty fn prototype section from cm44xx.h; incorporated comments from Todd; documented some functions] Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 3306bdfb79a1..fc54355de729 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -360,7 +360,7 @@ struct omap_hwmod_omap2_prcm { * @submodule_wkdep_bit: bit shift of the WKDEP range */ struct omap_hwmod_omap4_prcm { - void __iomem *clkctrl_reg; + u16 clkctrl_offs; void __iomem *rstctrl_reg; u8 submodule_wkdep_bit; }; -- cgit v1.2.3 From eaac329dfa6d3a4025242bf34d33aa3cb9df9f9f Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:31 -0600 Subject: OMAP4: hwmod: Replace RSTCTRL absolute address with offset macros The RSTCTRL register was accessed using an absolute address. The usage of hardcoded macros to calculate virtual address from physical one should be avoided as much as possible. The usage of an offset will allow future improvement like migration from the current architecture code toward a module driver. Update prm_xxx accessors, move definition to the proper header file and update copyrights. Change the s16 register offset parameter to u16. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak [paul@pwsan.com: use '_prminst_' in function names that are part of the prminst44xx.c file] Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index fc54355de729..9ef4424366d2 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/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, @@ -361,7 +362,7 @@ struct omap_hwmod_omap2_prcm { */ struct omap_hwmod_omap4_prcm { u16 clkctrl_offs; - void __iomem *rstctrl_reg; + u16 rstctrl_offs; u8 submodule_wkdep_bit; }; -- cgit v1.2.3 From 27bb00b58e04e5d8442335f694f2a1b6c31b184d Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:32 -0600 Subject: OMAP4: hwmod data: Add PRM context register offset Add a 'context_offs' entry in the prcm.omap4 structure to all IPs when applicable. The offset will be used to retrieve the per module context lost information now available on OMAP4. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 9ef4424366d2..16439fa13447 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -363,6 +363,7 @@ struct omap_hwmod_omap2_prcm { struct omap_hwmod_omap4_prcm { u16 clkctrl_offs; u16 rstctrl_offs; + u16 context_offs; u8 submodule_wkdep_bit; }; -- cgit v1.2.3 From 03fdefe53a3f057760751d958209f0c5507c8e40 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Sun, 10 Jul 2011 05:56:32 -0600 Subject: OMAP4: hwmod data: Add modulemode entry in omap_hwmod structure Add a new field to provide the mode supported by the module. The mode will control the way mandatory clocks are managed by the PRCM. 0 : Module is temporarily disabled by SW. OCP access to module are stalled. Can be used to change timing parameter of GPMC module. 1 : Module is managed automatically by HW according to clock domain transition. A clock domain sleep transition put module into idle. A wakeup domain transition put it back into function. If CLKTRCTRL=3, any OCP access to module is always granted. Module clocks may be gated according to the clock domain state. 2 : Module is explicitly enabled. Interface clock (if not used for functions) may be gated according to the clock domain state. Functional clocks are guarantied to stay present. As long as in this configuration, power domain sleep transition cannot happen. Some modules will have a modulemode initialized at 1 (HWCTRL) by default. This is the case for interconnect and simple module like GPIO, WDT, MAILBOX. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Cc: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_hwmod.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 16439fa13447..0e329ca88a70 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -80,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 @@ -365,6 +370,7 @@ struct omap_hwmod_omap4_prcm { u16 rstctrl_offs; u16 context_offs; u8 submodule_wkdep_bit; + u8 modulemode; }; -- cgit v1.2.3 From a53025724052b2b1edbc982a4a248784638f563d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sun, 10 Jul 2011 05:57:33 -0600 Subject: OMAP: Add debugfs node to show the summary of all clocks Add a debugfs node called "summary" to /sys/kernel/debug/clock/ that displays a quick summary of all clocks registered in the "clocks" structure. The format of the output from this node is: This debugfs node was very helpful for taking a quick snapshot of the linux clock tree for OMAP and ensuring clock frequencies calculated by the kernel were indeed correct. This patch helped uncover some bugs in the linux clock tree for OMAP4. Signed-off-by: Jon Hunter Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/clock.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index c9122dd6ee8d..156b27dd5817 100644 --- a/arch/arm/plat-omap/clock.c +++ b/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 +#include + 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; @@ -551,6 +584,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); -- cgit v1.2.3