Skip to contentSkip to conversation

OMAP: dmtimer: adaptation to platform_driver

PATCH Superseded Tarun Kanti DebBarma 4 participants 31 messages Sep 8, 2011 – Sep 19, 2011

Subsystems (6)

v15 of 16 Superseded Latest is v16 →

lore
Share & tools
lore
#0 lore raw

v15 cover OMAP: dmtimer: adaptation to platform_driver

Adaptation of dmtimer code to platform driver using omap_device and omap_hwmod abstraction. It also include pm-runtime and off-mode support.

Baseline: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Branch: Master
Commit: c6a389f Linux 3.1-rc4

Test Info:
- OMAP4430SDP: Functional tests.
- OMAP3430SDP: Functional and Off-mode tests. Verified system going to offmode between timer stop and start without reconfiguration in between.
- OMAP2430SDP: Functional tests.
- OMAP2420SDP: Functional tests.
- OMAP1710SDP: Boot test.

v15:
(1) Use pm_runtime_put() instead of pm_runtime_put_sync_suspend().
(2) Call pm_runtime_irq_safe() so that dmtimer is usable in interrupt context.
(3) Dynamic context save whenever registers are modified. This avoids overhead of calling context save routine which saves all registers.
(4) Avoid use of omap_readl(), omap_writel() in mach-omap1/timer.c. Instead use __raw_readl() and __raw_writel().
(5) Handle failure of *_dm_timer_prepare() in *_dm_timer_request() and *_dm_timer_request_specific().
(6) In mach-omap2/timer.c make sure that any of the timers can be used as iclocksource/clockevent timer by initializing func_offset and intr_offset correctly.
(7) Maintain proper register context restoration order. Specifically, made sure that interrupt enable and control registers are restored at the end.
(8) Remove wrapper around omap_pm_get_dev_context_loss_count(). Instead use it directly.
(9) Extend protection of exported APIs using spinlock.
(10) Remove the patch which uses mutex instead of spinlock because dmtimer can be used in interrupt context.
(11) Removed system_timer_reserved variable declaration in mach-omap1/timer.c which was added to remove compilation error while building for OMAP1.

v14:
(1) Baselined on top of Tony Lindgren's latest timer patch series.
(2) Context save/restore routines.
(3) Off-mode support
(4) Following comments from Todd Poynor <[email protected]> implemented
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg52677.html
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg52676.html
(5) Incorrect balancing of *_runtime_get/put_sync for wakeup domain timers in the off-mode patch corrected.

v13:
(1) Handling of early timer removed because this is being taken care by Tony's patch series.
(2) Timers reserved for clockevent/clocksource during early boot are registered and marked reserved.
(3) Platform specific timer code merged to mach-omap2/timer.c.
(4) Timer capabilities are added in the hwmod database to each of the omap timers.
(5) plat-omap/dmtimer.c plat-omap/include/plat/dmtimer.h are converted to a driver by moving them to drivers/misc/timer-omap.c and include/linux/timer-omap.h

v12:
(1) Remove registration and initialization of all timers during early boot. Initialize only the system timer which is set by the board file or default value assigned to it. This timer is not considered later during rest of the timers initialization.

(2) Use mutex instead of spinlock since there is no interrupt context.

(3) Remove hacky code to manage GPTIMER12 in mach-omap2/dmtimer.c. This is now changed to use dev_attr instead to identify if it is a secure timer. In the hwmod database, any secure timer entry can use this dev_attr so that driver avoids registering tha particular timer.

(4) Removed reset function from OMAP1 and kept it back to its original place in plat-omap/dmtimer.c, with modification of course. Instead of (is_omap16xx) flag a new variable (needs_manual_reset) added. This flag is set for OMAP1. So, call to reset function is made if this value is set implying that reset is called only for OMAP1.

(5) Timer enable and disable functions cleanup with checks for early boot condition removed. Added new interface wrapper function to configure system timer clock source.

(6) Move OMAP4 specific register offsets from mach-omap2 to driver code along with other register offset definitions.

(7) omap2_dm_timer_early_init() renamed to omap2_system_timer_init(), omap2_dm_timer_normal_init() renamed to omap2_dm_timer_init().

(8) Use dev_err() instead of pr_err() in low level read/write functions.

v11:
(1) Removed early timer initialization call from omap2_init_common_devices() in io.c. It is now called from omap2_gp_timer_init() in timer-gp.c as part of following call sequence:
start_kernel()->time_init()->timer->init()->omap2_gp_timer_init()
(2) Basedlined on top of Paul's patch series mentioned above.

v10:
(1) Update PM runtime for active early timers so that PM runtime userspace info is correct.
(2) Include code to configure timers to POSTED mode which got missed in the previous version.
(3) Remove pm runtime_enable from OMAP1 specific code since this is not applicable.

v9:
(1) In OMAP3 hwmod database, added entry for timer12 which was missing. Beagle board uses timer12 as its millisecond timer.
(2) In OMAP3 hwmod database, rectified in-correct prcm configurations for timer10 and timer11.
From:

       .prcm           = {
                       .module_bit = OMAP24XX_EN_GPT10_SHIFT,
                       .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
       },
To:
       .prcm           = {
                       .module_bit = OMAP3430_EN_GPT10_SHIFT,
                       .idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
               },

(3) In OMAP3 hwmod database, removed timer master port entry for all timers because it is not supported.

static struct omap_hwmod_ocp_if *omap3xxx_timer7_masters[] = {
       &omap3xxx_l4_per__timer7,
};

(4) In OMAP4 hwmod database, added SIDLE_SMART_WKUP flag for non-millisecond timers.
(5) In OMAP3 hwmod database, rectified sysconfig configuration for non-millisecond timers.
From: omap_hwmod_sysc_type2 To: omap_hwmod_sysc_type1. This was preventing system to go to RETENTION and OFF modes.

v8:
(1) Baselined on Tony's tree in omap-for-linus branch
(2) The last patch in v7 series has been removed because it is fixed by following patch:
commit: 78f26e872f77b6312273216de1a8f836c6f2e143
OMAP: hwmod: Set autoidle after smartidle during _sysc_enable

v7:
(1) In omap1_dm_timer_set_src(), the computation of shift value to respective dmtimer clock source was corrected:
From:
int n = (pdev->id) << 1;
To:
int n = (pdev->id - 1) << 1;
This change is needed because dmtimer is indexed from 1 now instead of 0.
(2) In omap1_dm_timer_init(void) memory resource end address chnaged:
From:
res[0].end = base + 0xff;
To:
res[0].end = base + 0x46;
This was causing request_mem_region() failure in driver probe().
(3) In the export APIs there are some calls which are not applicable to OMAP1. They have been made conditional now. They include following calls:

timer->fclk = clk_get(&timer->pdev->dev, "fck");
omap_dm_timer_enable()
omap_dm_timer_disable()

(4) Remove usage of cpu_is_omap16xx() and instead a flag has been added in struct dmtimer_platform_data {
...
u32 is_omap16xx:1;
}
This flag is set to 1 in mach-omap1/dmtimer.c and set to 0 in mach-omap2/dmtimer.c This flag is used in plat-omap/dmtimer.c wherever it needs to distiguish omap16xx.
(5) Remove #include <plat/omap_device.h> from mach-omap1/dmtimer.c
(6) Instead of using macros like INT_24XX_GPTIMERx, use the numbers directly in OMAP2420, OMAP2430 and OMAP3xxx hwmod database.
(7) pm_runtime_get_sync() and pm_runtime_put_sync() return value check modified from positive to negative value:
if (pm_runtime_get_sync(...) < 0) {
...
}

v6:
(1) Removed reset functions to mach-omap1/dmtimer.c.
Access to reset function from plat-omap/dmtimer.c is provided by means of function pointer.
(2) Remove multiple calls to omap_device_build() for registering timer devices during early and regular initialization. Regular device registration is now done by reading data from temporary list. This list is populated during early init where timer data is read from hwmod database and corresponding memory allocated.
(3) kfree(pdata) under error condition since platform_device_unregister does not free its pdata.
(4) Removed extra header inclusion in mach-omap2 and plat-omap
NOTE: omap_dm_timer.<id> field could not be removed because during regular boot there is no mechanism to match the current pdev with corresponding entry in the timer list which was partially initialized during early boot.

v5:
(1) In mach-omap2/dmtimer.c merged the merged two different init functions into a single one, viz: omap_timer_init(*oh, *user). Now this function is used both during early init and later. The distinction is between the two is made thriugh the *user field.
(2) Added timeout to low-level access routines in place of infinite while loop which waits on write-pend register bit.
(3) Modified devices names from "omap-timer.x" to "omap_timer.x"
(4) Modified module description from "OMAP DUAL MODE TIMER DRIVER" to:
MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
(5) Use well-defined constants for new IP revision register constants instead of hard-coded values.
(6) Use consistent naming mechanism by using _dm_timer_ instead of _dmtimer_ wherever applicable.
(7) Removed id field from omap_dm_timer{} since the same can be obtained from pdev.
(8) clk_get() and clk_put() moved from probe() and remove() functions. Now clk_get() is called when timer is acquired in the omap_dm_timer_prepare() and clk_put() is called in omap_dm_timer_free().
(9) Incorporated general comments:
(i) Redundant Copyright information.
(ii) Typos in comments.
(iii) Modify subjects for hwmod database related patches.
(iv) Remove redundant comments from hwmod database as they would be lost during auto-generation in the future.

v4:
(1) clock aliases are renamed as "32k_ck", "sys_ck" and "alt_ck"
(2) incorporate missing clk_put() for corresponding clk_get()
(3) modified clk_get()/clk_put() to be called once once in platform driver.
(4) consistent header for new files
(5) check return value of omap_hwmod_for_each_by_class() in device init routines.
(6) remove is_abe_timer field in dmtimer_platform_data structure. this is no longer needed with new input clock source aliasing.
(7) proper splitting of patch series
(8) remove register map from hwmod database.
(9) remove clock source strings array from hwmod database and associated structure declaration from plat/dmtimer.h. this is no longer needed.
(10) remove dev_attr from hwmod database. this is no longer needed.
(11) use register offsets to identify OMAP 4 registers instead of register map.
(12) remove clock source name strings from hwmod database.
(13) introduce new mechanism for getting struct clk associated with clock source names. this is achieved by adding clock alisases for all supported clock sources.
(14) remove clock setup functions in mach-omap2 for populating struct clk associated with all input clock sources because this is no longer needed with above implementation.
(15) device names changed from dmtimer to omap-timer
(16) device index starts from 1 instead of 0
(17) remove .init_name from hwmod database. this is not needed.
(18) introduce separate functions for reading/writing interrupt registers instead of doing all operations within a single function.

v3:
(1) multi-line comment error correction
(2) provision to allow any of the available dmtimers as early timers instead of restricting them to millisecond timers only.
(3) in 'struct omap_dmtimer{}' is_initialized flag is redundant and so must be removed. if the element is found in the list it is already initialized.
(4) remove 'found' flag in omap_dm_timer_request() and omap_dm_timer_request_specific() functions.
this is not needed with alternate implementation.
(5) use .init_name to initialize device names so that it can be identified during early boot as well. This is to avoid duplicate functions for clock manipulations during early boot and later.
(6) remove redundant functions from mach-omap2 which are created just to call pm functions like: pm_runtime_get_sync(),pm_runtime_put_sync(),.. and instead call them directly from plat-omap function api's.
(7) timer clock source names made part of hwmod database. source_clock[] of type 'struct clk' is made part of platform data.
(8) clockactivity field initialized in hwmod database to preserve fclk during idle. code which manipulate OCP config removed since they are already taken care by hwmod framework.
(9) omap2_dm_timer_set_src() is optimized. Clock enable/disbale routines moved to plat-omap layer and simplfied to the level so as not to sacrifice intended functionality.
NOTE: During early boot clock management was requested to be placed upon client drivers responsibility. this has not been done keeping in mind that it would entail (i) multiple modifications of client drivers (ii) it would violate the purpose of having a framework (open to debate).
(10) dmtimer register maps moved to hwmod database

v2:
(1) removed dedicated functions for early timer clock access. instead, now we have common functions for early and normal timers.
(2) removed usage of clock source strings for reading corresponding struct clks. this is now achieved through clock aliases introduced for each input clock sources.
(3) IP revision to distinguish new IP standard and the rest and then initialize dmtimer interrupt and functional offsets.
(4) provision to initialize all dmtimers as early timers.
(5) remove dm_timer_setup() function because this is no longer needed.
(6) modify the device index to start from 1 instead of 0.
(7) device name changed from dmtimer to omap-timer
(8) extract device ids' from hwmod name and same used for device build.
(9) additional resource allocation checks and free
(10) early timer variable initialization
(11) initialize timer_ip_type and register offsets in platform data structure.
(12) some more comments/logs

Tarun Kanti DebBarma (12):
OMAP2+: dmtimer: add device names to flck nodes
OMAP4: hwmod data: add dmtimer version information
OMAP1: dmtimer: conversion to platform devices OMAP2+: dmtimer: convert to platform devices
OMAP: dmtimer: platform driver
OMAP: dmtimer: switch-over to platform device driver
OMAP: dmtimer: pm_runtime support
OMAP: dmtimer: add timeout to low-level routines
OMAP: dmtimer: mark clocksource and clockevent timers reserved
OMAP: dmtimer: low-power mode support
OMAP: dmtimer: extend spinlock to exported APIs
OMAP: dmtimer: add error handling to export APIs

 arch/arm/mach-omap1/Makefile               |    2 +-
 arch/arm/mach-omap1/timer.c                |  174 +++++++
 arch/arm/mach-omap2/clock2420_data.c       |   48 ++
 arch/arm/mach-omap2/clock2430_data.c       |   48 ++
 arch/arm/mach-omap2/clock3xxx_data.c       |   36 ++
 arch/arm/mach-omap2/clock44xx_data.c       |   33 ++
 arch/arm/mach-omap2/omap_hwmod_2420_data.c |   22 +
 arch/arm/mach-omap2/omap_hwmod_2430_data.c |   22 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   27 +
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c |   24 +
 arch/arm/mach-omap2/timer.c                |  200 +++++++-
 arch/arm/plat-omap/dmtimer.c               |  775 +++++++++++++++++-----------
 arch/arm/plat-omap/include/plat/dmtimer.h  |  198 +++++--
 13 files changed, 1238 insertions(+), 371 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c
#1 lore raw

PATCH v15 1/12 OMAP2+: dmtimer: add device names to flck nodes

Add device name to OMAP2 dmtimer fclk nodes so that the fclk nodes can be retrieved by doing a clk_get with the corresponding device pointers or device names.

Signed-off-by Tarun Kanti DebBarma <tarun.kanti at ti.com
---
 arch/arm/mach-omap2/clock2420_data.c |   48 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/clock2430_data.c |   48 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/clock3xxx_data.c |   36 +++++++++++++++++++++++++
 arch/arm/mach-omap2/clock44xx_data.c |   33 +++++++++++++++++++++++
 4 files changed, 165 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/clock2420_data.c +48 -0
index debc040..14a6277 100644
@@ -1898,6 +1898,54 @@ static struct omap_clk omap2420_clks[] = {
 	CLK(NULL,	"pka_ick",	&pka_ick,	CK_242X),
 	CLK(NULL,	"usb_fck",	&usb_fck,	CK_242X),
 	CLK("musb-hdrc",	"fck",	&osc_ck,	CK_242X),
+	CLK("omap_timer.1",	"fck",	&gpt1_fck,	CK_242X),
+	CLK("omap_timer.2",	"fck",	&gpt2_fck,	CK_242X),
+	CLK("omap_timer.3",	"fck",	&gpt3_fck,	CK_242X),
+	CLK("omap_timer.4",	"fck",	&gpt4_fck,	CK_242X),
+	CLK("omap_timer.5",	"fck",	&gpt5_fck,	CK_242X),
+	CLK("omap_timer.6",	"fck",	&gpt6_fck,	CK_242X),
+	CLK("omap_timer.7",	"fck",	&gpt7_fck,	CK_242X),
+	CLK("omap_timer.8",	"fck",	&gpt8_fck,	CK_242X),
+	CLK("omap_timer.9",	"fck",	&gpt9_fck,	CK_242X),
+	CLK("omap_timer.10",	"fck",	&gpt10_fck,	CK_242X),
+	CLK("omap_timer.11",	"fck",	&gpt11_fck,	CK_242X),
+	CLK("omap_timer.12",	"fck",	&gpt12_fck,	CK_242X),
+	CLK("omap_timer.1",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.2",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.3",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.4",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.5",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.6",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.7",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.8",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.9",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.10",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.11",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.12",	"32k_ck",	&func_32k_ck,	CK_243X),
+	CLK("omap_timer.1",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.2",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.3",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.4",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.5",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.6",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.7",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.8",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.9",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.10",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.11",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.12",	"sys_ck",	&sys_ck,	CK_243X),
+	CLK("omap_timer.1",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.2",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.3",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.4",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.5",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.6",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.7",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.8",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.9",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.10",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.11",	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap_timer.12",	"alt_ck",	&alt_ck,	CK_243X),
 };
 
 /*
arch/arm/mach-omap2/clock2430_data.c +48 -0

54 lines not on this page · raw message

arch/arm/mach-omap2/clock3xxx_data.c +36 -0
index ffd55b1..2e1ed0d 100644
@@ -3462,6 +3462,42 @@ static struct omap_clk omap3xxx_clks[] = {
 	CLK("musb-am35x",	"fck",		&hsotgusb_fck_am35xx,	CK_AM35XX),
 	CLK(NULL,	"hecc_ck",	&hecc_ck,	CK_AM35XX),
 	CLK(NULL,	"uart4_ick",	&uart4_ick_am35xx,	CK_AM35XX),
+	CLK("omap_timer.1",	"fck",	&gpt1_fck,	CK_3XXX),
+	CLK("omap_timer.2",	"fck",	&gpt2_fck,	CK_3XXX),
+	CLK("omap_timer.3",	"fck",	&gpt3_fck,	CK_3XXX),
+	CLK("omap_timer.4",	"fck",	&gpt4_fck,	CK_3XXX),
+	CLK("omap_timer.5",	"fck",	&gpt5_fck,	CK_3XXX),
+	CLK("omap_timer.6",	"fck",	&gpt6_fck,	CK_3XXX),
+	CLK("omap_timer.7",	"fck",	&gpt7_fck,	CK_3XXX),
+	CLK("omap_timer.8",	"fck",	&gpt8_fck,	CK_3XXX),
+	CLK("omap_timer.9",	"fck",	&gpt9_fck,	CK_3XXX),
+	CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_3XXX),
+	CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_3XXX),
+	CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_3XXX),
+	CLK("omap_timer.1",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.2",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.3",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.4",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.5",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.6",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.7",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.8",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.9",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.10",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.11",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.12",	"32k_ck",	&omap_32k_fck,  CK_3XXX),
+	CLK("omap_timer.1",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.2",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.3",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.4",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.5",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.6",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.7",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.8",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.9",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.10",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.11",	"sys_ck",	&sys_ck,	CK_3XXX),
+	CLK("omap_timer.12",	"sys_ck",	&sys_ck,	CK_3XXX),
 };
 
 
arch/arm/mach-omap2/clock44xx_data.c +33 -0
index 2af0e3f..705c1fd 100644
@@ -3363,6 +3363,39 @@ static struct omap_clk omap44xx_clks[] = {
 	CLK("usbhs-omap.0",	"usbhost_ick",		&dummy_ck,		CK_443X),
 	CLK("usbhs-omap.0",	"usbtll_fck",		&dummy_ck,	CK_443X),
 	CLK("omap_wdt",	"ick",				&dummy_ck,	CK_443X),
+	CLK("omap_timer.1",	"fck",			&timer1_fck,	CK_443X),
+	CLK("omap_timer.2",	"fck",			&timer2_fck,	CK_443X),
+	CLK("omap_timer.3",	"fck",			&timer3_fck,	CK_443X),
+	CLK("omap_timer.4",	"fck",			&timer4_fck,	CK_443X),
+	CLK("omap_timer.5",	"fck",			&timer5_fck,	CK_443X),
+	CLK("omap_timer.6",	"fck",			&timer6_fck,	CK_443X),
+	CLK("omap_timer.7",	"fck",			&timer7_fck,	CK_443X),
+	CLK("omap_timer.8",	"fck",			&timer8_fck,	CK_443X),
+	CLK("omap_timer.9",	"fck",			&timer9_fck,	CK_443X),
+	CLK("omap_timer.10",	"fck",			&timer10_fck,	CK_443X),
+	CLK("omap_timer.11",	"fck",			&timer11_fck,	CK_443X),
+	CLK("omap_timer.1",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.2",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.3",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.4",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.5",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.6",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.7",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.8",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.9",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.10",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.11",	"32k_ck",	&sys_32k_ck,	CK_443X),
+	CLK("omap_timer.1",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.2",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.3",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.4",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.9",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.10",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.11",	"sys_ck",	&sys_clkin_ck,	CK_443X),
+	CLK("omap_timer.5",	"sys_ck",	&syc_clk_div_ck,	CK_443X),
+	CLK("omap_timer.6",	"sys_ck",	&syc_clk_div_ck,	CK_443X),
+	CLK("omap_timer.7",	"sys_ck",	&syc_clk_div_ck,	CK_443X),
+	CLK("omap_timer.8",	"sys_ck",	&syc_clk_div_ck,	CK_443X),
 };
 
 int __init omap4xxx_clk_init(void)
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH v15 2/12 OMAP4: hwmod data: add dmtimer version information

In reply to Tarun Kanti DebBarma

OMAP4 has two groups of timers: version 1 timers are 1, 2, 10, while the rest of the timers, 3-9, 11 are version 2 timers. The version information is required by the driver so that they could be handled correctly by it.

---
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c |    3 +++
 arch/arm/plat-omap/include/plat/dmtimer.h  |    4 +++-
 2 files changed, 6 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +3 -0
index 6201422..2010a7b 100644
@@ -29,6 +29,7 @@
 #include <plat/mcbsp.h>
 #include <plat/mmc.h>
 #include <plat/i2c.h>
+#include <plat/dmtimer.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -4248,6 +4249,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = {
 static struct omap_hwmod_class omap44xx_timer_1ms_hwmod_class = {
 	.name	= "timer",
 	.sysc	= &omap44xx_timer_1ms_sysc,
+	.rev    = OMAP_TIMER_IP_VERSION_1,
 };
 
 static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = {
@@ -4263,6 +4265,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = {
 static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
 	.name	= "timer",
 	.sysc	= &omap44xx_timer_sysc,
+	.rev    = OMAP_TIMER_IP_VERSION_2,
 };
 
 /* timer1 */
arch/arm/plat-omap/include/plat/dmtimer.h +3 -1
index eb5d16c..37efa15 100644
@@ -58,7 +58,9 @@
  * IP revision identifier so that Highlander IP
  * in OMAP4 can be distinguished.
  */
-#define OMAP_TIMER_IP_VERSION_1                        0x1
+#define OMAP_TIMER_IP_VERSION_1			0x1
+#define OMAP_TIMER_IP_VERSION_2			0x2
+
 struct omap_dm_timer;
 struct clk;
 
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH v15 3/12 OMAP1: dmtimer: conversion to platform devices

In reply to Tarun Kanti DebBarma

Convert OMAP1 dmtimers into a platform devices and then registers with device model framework so that it can be bound to corresponding driver.

---
 arch/arm/mach-omap1/Makefile              |    2 +-
 arch/arm/mach-omap1/timer.c               |  174 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/dmtimer.c              |   56 ++-------
 arch/arm/plat-omap/include/plat/dmtimer.h |    8 ++
 4 files changed, 195 insertions(+), 45 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c
arch/arm/mach-omap1/Makefile +1 -1
index 5b114d1..11c85cd 100644
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
-obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o
+obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
arch/arm/mach-omap1/timer.c new file +174 -0

174 lines not on this page · raw message

arch/arm/plat-omap/dmtimer.c +12 -44

94 lines not on this page · raw message

arch/arm/plat-omap/include/plat/dmtimer.h +8 -0
index 37efa15..e744e82 100644
@@ -35,6 +35,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 
 #ifndef __ASM_ARCH_DMTIMER_H
 #define __ASM_ARCH_DMTIMER_H
@@ -64,6 +65,12 @@
 struct omap_dm_timer;
 struct clk;
 
+struct dmtimer_platform_data {
+	int (*set_timer_src)(struct platform_device *pdev, int source);
+	int timer_ip_type;
+	u32 needs_manual_reset:1;
+};
+
 struct omap_dm_timer *omap_dm_timer_request(void);
 struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
 void omap_dm_timer_free(struct omap_dm_timer *timer);
@@ -220,6 +227,7 @@ struct omap_dm_timer {
 	unsigned reserved:1;
 	unsigned enabled:1;
 	unsigned posted:1;
+	struct platform_device *pdev;
 };
 
 extern u32 sys_timer_reserved;
Signature · 1 line
1.7.0.4
#4 lore raw

PATCH v15 4/12 OMAP2+: dmtimer: convert to platform devices

In reply to Tarun Kanti DebBarma

Add routines to converts dmtimers to platform devices. The device data is obtained from hwmod database of respective platform and is registered to device model after successful binding to driver.
In addition, capability attribute of each of the timers is added in hwmod database.

---
 arch/arm/mach-omap2/omap_hwmod_2420_data.c |   22 +++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c |   22 +++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   27 ++++++
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c |   21 +++++
 arch/arm/mach-omap2/timer.c                |  136 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/dmtimer.h  |   10 ++-
 6 files changed, 237 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +22 -0
index a015c69..d4da3f6 100644
@@ -274,6 +274,16 @@ static struct omap_hwmod omap2420_iva_hwmod = {
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap2420_timer1_hwmod;
 
@@ -314,6 +324,7 @@ static struct omap_hwmod omap2420_timer1_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer1_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -351,6 +362,7 @@ static struct omap_hwmod omap2420_timer2_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer2_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -388,6 +400,7 @@ static struct omap_hwmod omap2420_timer3_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer3_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer3_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -425,6 +438,7 @@ static struct omap_hwmod omap2420_timer4_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer4_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer4_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -462,6 +476,7 @@ static struct omap_hwmod omap2420_timer5_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer5_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer5_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -500,6 +515,7 @@ static struct omap_hwmod omap2420_timer6_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer6_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer6_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -537,6 +553,7 @@ static struct omap_hwmod omap2420_timer7_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer7_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer7_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -574,6 +591,7 @@ static struct omap_hwmod omap2420_timer8_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2420_timer8_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer8_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -611,6 +629,7 @@ static struct omap_hwmod omap2420_timer9_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2420_timer9_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer9_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -648,6 +667,7 @@ static struct omap_hwmod omap2420_timer10_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2420_timer10_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer10_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -685,6 +705,7 @@ static struct omap_hwmod omap2420_timer11_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2420_timer11_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer11_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -722,6 +743,7 @@ static struct omap_hwmod omap2420_timer12_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2420_timer12_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2420_timer12_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
arch/arm/mach-omap2/omap_hwmod_2430_data.c +22 -0
index 16743c7..23daa5c 100644
@@ -347,6 +347,16 @@ static struct omap_hwmod omap2430_iva_hwmod = {
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap2430_timer1_hwmod;
 
@@ -387,6 +397,7 @@ static struct omap_hwmod omap2430_timer1_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer1_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -424,6 +435,7 @@ static struct omap_hwmod omap2430_timer2_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer2_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -461,6 +473,7 @@ static struct omap_hwmod omap2430_timer3_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer3_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer3_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -498,6 +511,7 @@ static struct omap_hwmod omap2430_timer4_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer4_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer4_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -535,6 +549,7 @@ static struct omap_hwmod omap2430_timer5_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer5_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer5_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -572,6 +587,7 @@ static struct omap_hwmod omap2430_timer6_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer6_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer6_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -609,6 +625,7 @@ static struct omap_hwmod omap2430_timer7_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer7_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer7_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -646,6 +663,7 @@ static struct omap_hwmod omap2430_timer8_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap2430_timer8_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer8_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -683,6 +701,7 @@ static struct omap_hwmod omap2430_timer9_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2430_timer9_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer9_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -720,6 +739,7 @@ static struct omap_hwmod omap2430_timer10_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2430_timer10_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer10_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -757,6 +777,7 @@ static struct omap_hwmod omap2430_timer11_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2430_timer11_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer11_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
@@ -794,6 +815,7 @@ static struct omap_hwmod omap2430_timer12_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap2430_timer12_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap2430_timer12_slaves),
 	.class		= &omap2xxx_timer_hwmod_class,
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +27 -0
index 25bf43b..47e28c1 100644
@@ -570,6 +570,21 @@ static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
 	.rev =  OMAP_TIMER_IP_VERSION_1,
 };
 
+/* secure timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
+	.timer_capability       = OMAP_TIMER_SECURE,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability       = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability       = OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap3xxx_timer1_hwmod;
 
@@ -610,6 +625,7 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer1_slaves),
 	.class		= &omap3xxx_timer_1ms_hwmod_class,
@@ -656,6 +672,7 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer2_slaves),
 	.class		= &omap3xxx_timer_1ms_hwmod_class,
@@ -702,6 +719,7 @@ static struct omap_hwmod omap3xxx_timer3_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer3_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer3_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -748,6 +766,7 @@ static struct omap_hwmod omap3xxx_timer4_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer4_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer4_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -794,6 +813,7 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer5_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer5_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -840,6 +860,7 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer6_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer6_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -886,6 +907,7 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap3xxx_timer7_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer7_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -932,6 +954,7 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap3xxx_timer8_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer8_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -978,6 +1001,7 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap3xxx_timer9_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer9_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -1015,6 +1039,7 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap3xxx_timer10_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer10_slaves),
 	.class		= &omap3xxx_timer_1ms_hwmod_class,
@@ -1052,6 +1077,7 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap3xxx_timer11_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer11_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
@@ -1102,6 +1128,7 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
 		},
 	},
+	.dev_attr	= &capability_secure_dev_attr,
 	.slaves		= omap3xxx_timer12_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_timer12_slaves),
 	.class		= &omap3xxx_timer_hwmod_class,
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +21 -0
index 2010a7b..e698365 100644
@@ -4268,6 +4268,16 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
 	.rev    = OMAP_TIMER_IP_VERSION_2,
 };
 
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability	= OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+	.timer_capability	= OMAP_TIMER_HAS_PWM,
+};
+
 /* timer1 */
 static struct omap_hwmod omap44xx_timer1_hwmod;
 static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
@@ -4311,6 +4321,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer1_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4359,6 +4370,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer2_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4407,6 +4419,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer3_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer3_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4455,6 +4468,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer4_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer4_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4522,6 +4536,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer5_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer5_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4590,6 +4605,7 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer6_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer6_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4657,6 +4673,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_alwon_dev_attr,
 	.slaves		= omap44xx_timer7_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer7_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4724,6 +4741,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap44xx_timer8_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer8_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4772,6 +4790,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap44xx_timer9_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer9_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4820,6 +4839,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap44xx_timer10_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer10_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -4868,6 +4888,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
+	.dev_attr	= &capability_pwm_dev_attr,
 	.slaves		= omap44xx_timer11_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_timer11_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
arch/arm/mach-omap2/timer.c +136 -0

151 lines not on this page · raw message

arch/arm/plat-omap/include/plat/dmtimer.h +9 -1
index e744e82..3495dec 100644
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/dmtimer.h
+ * arch/arm/plat-omap/include/plat/dmtimer.h
  *
  * OMAP Dual-Mode Timers
  *
@@ -62,6 +62,14 @@
 #define OMAP_TIMER_IP_VERSION_1			0x1
 #define OMAP_TIMER_IP_VERSION_2			0x2
 
+/* timer capabilities used in hwmod database */
+#define OMAP_TIMER_SECURE				0x80000000
+#define OMAP_TIMER_ALWON				0x40000000
+#define OMAP_TIMER_HAS_PWM				0x20000000
+
+struct omap_timer_capability_dev_attr {
+	u32 timer_capability;
+};
 struct omap_dm_timer;
 struct clk;
 
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH v15 5/12 OMAP: dmtimer: platform driver

In reply to Tarun Kanti DebBarma

Add dmtimer platform driver functions which include:
(1) platform driver initialization
(2) driver probe function
(3) driver remove function

---
 arch/arm/plat-omap/dmtimer.c              |  143 +++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/dmtimer.h |   11 ++
 2 files changed, 148 insertions(+), 6 deletions(-)
arch/arm/plat-omap/dmtimer.c +137 -6
index c11073d..7cee4fb 100644
@@ -35,14 +35,9 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <mach/hardware.h>
 #include <plat/dmtimer.h>
 #include <mach/irqs.h>
@@ -149,6 +144,7 @@ static const char **dm_source_names;
 static struct clk **dm_source_clocks;
 
 static spinlock_t dm_timer_lock;
+static LIST_HEAD(omap_timer_list);
 
 /*
  * Reads timer registers in posted and non-posted mode. The posted mode bit
@@ -544,6 +540,141 @@ int omap_dm_timers_active(void)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 
+/**
+ * omap_dm_timer_probe - probe function called for every registered device
+ * @pdev:	pointer to current timer platform device
+ *
+ * Called by driver framework at the end of device registration for all
+ * timer devices.
+ */
+static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
+{
+	int ret;
+	unsigned long flags;
+	struct omap_dm_timer *timer;
+	struct resource *mem, *irq, *ioarea;
+	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
+		return -ENODEV;
+	}
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!irq)) {
+		dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
+		return -ENODEV;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!mem)) {
+		dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
+		return -ENODEV;
+	}
+
+	ioarea = request_mem_region(mem->start, resource_size(mem),
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
+		return -EBUSY;
+	}
+
+	timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
+	if (!timer) {
+		dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_free_ioregion;
+	}
+
+	timer->io_base = ioremap(mem->start, resource_size(mem));
+	if (!timer->io_base) {
+		dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
+		ret = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	if (pdata->timer_ip_type == OMAP_TIMER_IP_VERSION_2) {
+		timer->func_offset = VERSION2_TIMER_WAKEUP_EN_REG_OFFSET;
+		timer->intr_offset = VERSION2_TIMER_STAT_REG_OFFSET;
+	}
+
+	timer->id = pdev->id;
+	timer->irq = irq->start;
+	timer->pdev = pdev;
+
+	/* add the timer element to the list */
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_add_tail(&timer->node, &omap_timer_list);
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+	dev_dbg(&pdev->dev, "Device Probed.\n");
+
+	return 0;
+
+err_free_mem:
+	kfree(timer);
+
+err_free_ioregion:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return ret;
+}
+
+/**
+ * omap_dm_timer_remove - cleanup a registered timer device
+ * @pdev:	pointer to current timer platform device
+ *
+ * Called by driver framework whenever a timer device is unregistered.
+ * In addition to freeing platform resources it also deletes the timer
+ * entry from the local list.
+ */
+static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
+{
+	struct omap_dm_timer *timer;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_for_each_entry(timer, &omap_timer_list, node)
+		if (timer->pdev->id == pdev->id) {
+			list_del(&timer->node);
+			kfree(timer);
+			ret = 0;
+			break;
+		}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+	return ret;
+}
+
+static struct platform_driver omap_dm_timer_driver = {
+	.probe  = omap_dm_timer_probe,
+	.remove = omap_dm_timer_remove,
+	.driver = {
+		.name   = "omap_timer",
+	},
+};
+
+static int __init omap_dm_timer_driver_init(void)
+{
+	return platform_driver_register(&omap_dm_timer_driver);
+}
+
+static void __exit omap_dm_timer_driver_exit(void)
+{
+	platform_driver_unregister(&omap_dm_timer_driver);
+}
+
+early_platform_init("earlytimer", &omap_dm_timer_driver);
+module_init(omap_dm_timer_driver_init);
+module_exit(omap_dm_timer_driver_exit);
+
+MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
+
 static int __init omap_dm_timer_init(void)
 {
 	struct omap_dm_timer *timer;
arch/arm/plat-omap/include/plat/dmtimer.h +11 -0
index 3495dec..46f6e7f 100644
@@ -62,6 +62,13 @@
 #define OMAP_TIMER_IP_VERSION_1			0x1
 #define OMAP_TIMER_IP_VERSION_2			0x2
 
+/*
+ * OMAP4 IP revision has different register offsets
+ * for interrupt registers and functional registers.
+ */
+#define VERSION2_TIMER_WAKEUP_EN_REG_OFFSET     0x14
+#define VERSION2_TIMER_STAT_REG_OFFSET          0x10
+
 /* timer capabilities used in hwmod database */
 #define OMAP_TIMER_SECURE				0x80000000
 #define OMAP_TIMER_ALWON				0x40000000
@@ -226,6 +233,7 @@ int omap_dm_timers_active(void);
 
 struct omap_dm_timer {
 	unsigned long phys_base;
+	int id;
 	int irq;
 #ifdef CONFIG_ARCH_OMAP2PLUS
 	struct clk *iclk, *fclk;
@@ -235,7 +243,10 @@ struct omap_dm_timer {
 	unsigned reserved:1;
 	unsigned enabled:1;
 	unsigned posted:1;
+	u8 func_offset;
+	u8 intr_offset;
 	struct platform_device *pdev;
+	struct list_head node;
 };
 
 extern u32 sys_timer_reserved;
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

In reply to Tarun Kanti DebBarma

Register timer devices by going through hwmod database using hwmod API. The driver probes each of the registered devices. Functionality which are already performed by hwmod framework are removed from timer code. New set of timers present on OMAP4 are now supported.

---
 arch/arm/mach-omap2/timer.c               |   56 ++++-
 arch/arm/plat-omap/dmtimer.c              |  374 ++++++++++-------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |   82 ++++---
 3 files changed, 219 insertions(+), 293 deletions(-)
arch/arm/mach-omap2/timer.c +44 -12
index a33916a..4758d3e 100644
@@ -80,7 +80,8 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = &clockevent_gpt;
 
-	__omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+	__omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW,
+				clkev.intr_offset, clkev.func_offset);
 
 	evt->event_handler(evt);
 	return IRQ_HANDLED;
@@ -96,7 +97,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
 					 struct clock_event_device *evt)
 {
 	__omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
-						0xffffffff - cycles, 1);
+				0xffffffff - cycles, 1, clkev.func_offset);
 
 	return 0;
 }
@@ -106,7 +107,8 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
 	u32 period;
 
-	__omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
+	__omap_dm_timer_stop(clkev.io_base, 1, clkev.rate, true,
+				clkev.intr_offset, clkev.func_offset);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
@@ -114,10 +116,10 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 		period -= 1;
 		/* Looks like we need to first set the load value separately */
 		__omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
-					0xffffffff - period, 1);
+				0xffffffff - period, 1, clkev.func_offset);
 		__omap_dm_timer_load_start(clkev.io_base,
-					OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
-						0xffffffff - period, 1);
+				OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
+				0xffffffff - period, 1, clkev.func_offset);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
 		break;
@@ -173,6 +175,11 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 		return -ENODEV;
 	}
 
+	if (oh->class->rev == OMAP_TIMER_IP_VERSION_2) {
+		timer->func_offset = VERSION2_TIMER_WAKEUP_EN_REG_OFFSET;
+		timer->intr_offset = VERSION2_TIMER_STAT_REG_OFFSET;
+	}
+
 	omap_hwmod_enable(oh);
 
 	sys_timer_reserved |= (1 << (gptimer_id - 1));
@@ -191,7 +198,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 			clk_put(src);
 		}
 	}
-	__omap_dm_timer_reset(timer->io_base, 1, 1);
+	__omap_dm_timer_reset(timer->io_base, 1, 1, timer->func_offset);
 	timer->posted = 1;
 
 	timer->rate = clk_get_rate(timer->fclk);
@@ -212,7 +219,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
 	omap2_gp_timer_irq.dev_id = (void *)&clkev;
 	setup_irq(clkev.irq, &omap2_gp_timer_irq);
 
-	__omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+	__omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW,
+					clkev.intr_offset, clkev.func_offset);
 
 	clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
 				     clockevent_gpt.shift);
@@ -253,7 +261,8 @@ static struct omap_dm_timer clksrc;
 static DEFINE_CLOCK_DATA(cd);
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
-	return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
+	return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1,
+						clksrc.func_offset);
 }
 
 static struct clocksource clocksource_gpt = {
@@ -268,7 +277,8 @@ static void notrace dmtimer_update_sched_clock(void)
 {
 	u32 cyc;
 
-	cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+	cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1,
+						clksrc.func_offset);
 
 	update_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -278,7 +288,8 @@ unsigned long long notrace sched_clock(void)
 	u32 cyc = 0;
 
 	if (clksrc.reserved)
-		cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+		cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1,
+							clksrc.func_offset);
 
 	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -296,7 +307,8 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
 		gptimer_id, clksrc.rate);
 
 	__omap_dm_timer_load_start(clksrc.io_base,
-			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1,
+						clksrc.func_offset);
 	init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
 	if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
@@ -477,3 +489,23 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 
 	return ret;
 }
+
+/**
+ * omap2_dm_timer_init - top level regular device initialization
+ *
+ * Uses dedicated hwmod api to parse through hwmod database for
+ * given class name and then build and register the timer device.
+ */
+static int __init omap2_dm_timer_init(void)
+{
+	int ret;
+
+	ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
+	if (unlikely(ret)) {
+		pr_err("%s: device registration failed.\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+arch_initcall(omap2_dm_timer_init);
arch/arm/plat-omap/dmtimer.c +129 -245

536 lines not on this page · raw message

arch/arm/plat-omap/include/plat/dmtimer.h +46 -36

154 lines not on this page · raw message

Signature · 1 line
1.7.0.4
maintainer
#7 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Hi,

Quoted 5 lines · Tarun Kanti DebBarma

Register timer devices by going through hwmod database using hwmod API. The driver probes each of the registered devices. Functionality which are already performed by hwmod framework are removed from timer code. New set of timers present on OMAP4 are now supported.

Adding the support for the different offsets on some omap4 timers should be a separate patch.

Also, as we don't need the support for different register offsets for the first two omap4 timers, please rather implement support for the new timers and the timeouts directly in plat-omap/dmtimer.c.

That way we can still keep the minimal timer support simple for clocksource and clockevent. Of course this means that we'll be only supporting the first two timers as system timers on omap4, but that's fine.

Quoted 14 lines

static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,

arch/arm/plat-omap/include/plat/dmtimer.h +3 -2
-						int posted)
+						int posted, u8 func_offset)
 {
 	if (posted)
-		while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
+		while (__raw_readl(base +
+			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff))
 				& (reg >> WPSHIFT))
 			cpu_relax();
@@ -264,10 +263,11 @@ static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
 }
 

arch/arm/plat-omap/include/plat/dmtimer.h static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg, · line 272

Quoted 10 lines
arch/arm/plat-omap/include/plat/dmtimer.h +3 -2
 static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
-						int posted)
+						int posted, u8 func_offset)
 {
 	if (posted)
-		while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
+		while (__raw_readl(base +
+			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff))
 				& (reg >> WPSHIFT))
 			cpu_relax();

Otherwise our inline functions just get too messed up with these func_offset hacks. These need to be minimal as they're being called contantly for the system timers. We can still recycle the inline functions if we pass the correct WRITE_PEND_REG to them instead of the func_offset.

Regards,

Tony

maintainer
#8 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Quoted 9 lines · Tony Lindgren

Also, as we don't need the support for different register offsets for the first two omap4 timers, please rather implement support for the new timers and the timeouts directly in plat-omap/dmtimer.c.

That way we can still keep the minimal timer support simple for clocksource and clockevent. Of course this means that we'll be only supporting the first two timers as system timers on omap4, but that's fine.

Since you already have the struct timer_regs, you can make use of that in dmtimer.c. Then maybe make the inline functions to something like this instead:

static inline u32 __omap_dm_timer_read(void __iomem *base, u8 reg,

						u8 pend, int posted);

Where you pass the timer->context.pend depending on the pending register offset for the timer.

Regards,

Tony

#9 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

In reply to Tony Lindgren
Quoted 12 lines · Tony Lindgren

Hi,

Quoted 5 lines · Tarun Kanti DebBarma

Register timer devices by going through hwmod database using hwmod API. The driver probes each of the registered devices. Functionality which are already performed by hwmod framework are removed from timer code. New set of timers present on OMAP4 are now supported.

Adding the support for the different offsets on some omap4 timers should be a separate patch.

Quoted 8 lines

Also, as we don't need the support for different register offsets for the first two omap4 timers, please rather implement support for the new timers and the timeouts directly in plat-omap/dmtimer.c.

That way we can still keep the minimal timer support simple for clocksource and clockevent. Of course this means that we'll be only supporting the first two timers as system timers on omap4, but that's fine.

Ok, I can make the change!
But, do we have to keep OMAP5 in mind right now where even timers[1,2] require addition of offsets?
--
Tarun
[...]

#10 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Hi Tony,

Quoted 8 lines · Tarun Kanti
Quoted 7 lines · Tony Lindgren
Quoted 2 lines · Tarun Kanti DebBarma

removed from timer code. New set of timers present on OMAP4 are now supported.

Also, as we don't need the support for different register offsets for the first two omap4 timers, please rather implement support for the new timers and the timeouts directly in plat-omap/dmtimer.c.

Quoted 6 lines
Quoted 4 lines

That way we can still keep the minimal timer support simple for clocksource and clockevent. Of course this means that we'll be only supporting the first two timers as system timers on omap4, but that's fine.

Ok, I can make the change!
But, do we have to keep OMAP5 in mind right now where even timers[1,2] require addition of offsets?

We need clocksource & clockevent to be able to work with timers requiring addition of offsets. Without this AM335X, TI816X and TI814X SoC's will not boot.

Regards
Afzal

maintainer
#11 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Quoted 15 lines · Mohammed, Afzal

Hi Tony,

Quoted 12 lines · Tarun Kanti
Quoted 11 lines · Tony Lindgren
Quoted 2 lines · Tarun Kanti DebBarma

removed from timer code. New set of timers present on OMAP4 are now supported.

Also, as we don't need the support for different register offsets for the first two omap4 timers, please rather implement support for the new timers and the timeouts directly in plat-omap/dmtimer.c.

That way we can still keep the minimal timer support simple for clocksource and clockevent. Of course this means that we'll be only supporting the first two timers as system timers on omap4, but that's fine.

Quoted 6 lines
Quoted 2 lines

Ok, I can make the change!
But, do we have to keep OMAP5 in mind right now where even timers[1,2] require addition of offsets?

We need clocksource & clockevent to be able to work with timers requiring addition of offsets. Without this AM335X, TI816X and TI814X SoC's will not boot.

OK. Then how about let's do the following things:

1. Modify the inline access functions to take the PEND and others if needed registers as a parameter

2. Modify mach-omap2/timer.c to initialize the PEND and others in the SoC specific timer_init function

3. Move all the non-minimal stuff into dmtimer.c as that will eventually be a device driver at some point

This way we can still share some of the inline access functions and keep the system timer code minimal. Then the device driver like features will be limited to dmtimer.c as that usage is more complex with than with system timer.

Regards,

Tony

maintainer
#12 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Quoted 6 lines · Tony Lindgren
Quoted 4 lines · Mohammed, Afzal

We need clocksource & clockevent to be able to work with timers requiring addition of offsets. Without this AM335X, TI816X and TI814X SoC's will not boot.

Quoted 7 lines

OK. Then how about let's do the following things:

1. Modify the inline access functions to take the PEND and others if needed registers as a parameter

2. Modify mach-omap2/timer.c to initialize the PEND and others in the SoC specific timer_init function

Also, let's do these changes first then rebase the dmtimer series on those changes as it simplifies the dmtimer series a bit.

Regards,

Tony

#13 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

Quoted 12 lines · Tony Lindgren
Quoted 11 lines · Tony Lindgren
Quoted 4 lines · Mohammed, Afzal

We need clocksource & clockevent to be able to work with timers requiring addition of offsets. Without this AM335X, TI816X and TI814X SoC's will not boot.

OK. Then how about let's do the following things:

1. Modify the inline access functions to take the PEND and others ? ?if needed registers as a parameter

Quoted 6 lines
Quoted 2 lines

2. Modify mach-omap2/timer.c to initialize the PEND and others ? ?in the SoC specific timer_init function

Also, let's do these changes first then rebase the dmtimer series on those changes as it simplifies the dmtimer series a bit.

Alright.... I will start with this.
--
Tarun

Quoted 5 lines

Regards,

Tony

#14 lore raw

PATCH v15 6/12 OMAP: dmtimer: switch-over to platform device driver

[...]

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

1. Modify the inline access functions to take the PEND and others ? ?if needed registers as a parameter

2. Modify mach-omap2/timer.c to initialize the PEND and others ? ?in the SoC specific timer_init function

Just to make my understanding complete, need some clarifications:
As we would end up modifying almost all inline functions, what naming convention should we follow for the parameters? For instance, PEND is related to TWPS register. So are you suggesting using parameter names related to respective registers in each inline functions? If that is the case we would end up declaring lot of local variables along with PEND. Instead, we could very well have just two variables to represent functional and interrupt offsets.

Also, in plat-omap/dmtimer.c, timer_regs{} stores the register values and not the register offsets. Therefore, we would not be able to pass as parameters, timer->context.<x> ... etc.

Please let me know if I am off-track in my understanding. Thanks.
--
Tarun
[...]

maintainer
#15 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

Quoted 9 lines · DebBarma, Tarun Kanti

[...]

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

1. Modify the inline access functions to take the PEND and others ? ?if needed registers as a parameter

2. Modify mach-omap2/timer.c to initialize the PEND and others ? ?in the SoC specific timer_init function

Just to make my understanding complete, need some clarifications:
As we would end up modifying almost all inline functions, what naming convention should we follow for the parameters?

Well here's what I came up with to deal with the different timer registers. We can't use the context registers as those are for the value naturally..

But we can map the interrupt registers separately and then have the rest start from func_base that is different based on the timer version. Rebasing the rest of the dmtimer hwmod patches on this should be fairly easy, mostly just need to pass timer instead of timer->io_base and use __raw_read/write for the interrupt registers.

Also, I ended up checking the timer revision with if (!(tidr >> 16)) as it seems that those bits are zero for v1 timers? If that works, then we don't need patch 02/12 for the revision number.

Afzal, care to check if that works for AM335X/TI816X/TI814X? It tried it briefly with omap4 gptimer3 as the clockevent and CONFIG_LOCAL_TIMER disabled.

The patch is against the current cleanup branch in linux-omap tree.

Regards,

Tony

From: Tony Lindgren <[email protected]>
Date: Fri, 16 Sep 2011 15:44:20 -0700
Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip

The registers are slightly different between v1 and v2 ip that is available in omap4 and later for some timers.

Add support for v2 ip by mapping the interrupt related registers separately and adding func_base for the functional registers.

Also disable dmtimer driver features on omap4 for now as those need the hwmod conversion series to deal with enabling the timers properly in omap_dm_timer_init.

arch/arm/mach-omap2/timer.c +12 -11
index cf1de7d..21d34fb 100644
@@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = &clockevent_gpt;
 
-	__omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+	__omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
 	evt->event_handler(evt);
 	return IRQ_HANDLED;
@@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = {
 static int omap2_gp_timer_set_next_event(unsigned long cycles,
 					 struct clock_event_device *evt)
 {
-	__omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
+	__omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
 						0xffffffff - cycles, 1);
 
 	return 0;
@@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
 	u32 period;
 
-	__omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		period = clkev.rate / HZ;
 		period -= 1;
 		/* Looks like we need to first set the load value separately */
-		__omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
+		__omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
 					0xffffffff - period, 1);
-		__omap_dm_timer_load_start(clkev.io_base,
+		__omap_dm_timer_load_start(&clkev,
 					OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
 						0xffffffff - period, 1);
 		break;
@@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 	}
 
 	omap_hwmod_enable(oh);
+	__omap_dm_timer_init_regs(timer);
 
 	sys_timer_reserved |= (1 << (gptimer_id - 1));
 
@@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 			clk_put(src);
 		}
 	}
-	__omap_dm_timer_reset(timer->io_base, 1, 1);
+	__omap_dm_timer_reset(timer, 1, 1);
 	timer->posted = 1;
 
 	timer->rate = clk_get_rate(timer->fclk);
@@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
 	omap2_gp_timer_irq.dev_id = (void *)&clkev;
 	setup_irq(clkev.irq, &omap2_gp_timer_irq);
 
-	__omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
 	clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
 				     clockevent_gpt.shift);
@@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc;
 static DEFINE_CLOCK_DATA(cd);
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
-	return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
+	return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
 }
 
 static struct clocksource clocksource_gpt = {
@@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void)
 {
 	u32 cyc;
 
-	cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+	cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
 	update_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void)
 	u32 cyc = 0;
 
 	if (clksrc.reserved)
-		cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+		cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
 	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
 }
@@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
 	pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
 		gptimer_id, clksrc.rate);
 
-	__omap_dm_timer_load_start(clksrc.io_base,
+	__omap_dm_timer_load_start(&clksrc,
 			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
 	init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
arch/arm/plat-omap/dmtimer.c +22 -10
index 75a847d..e23b7cf 100644
@@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock;
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
-	return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
+	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+	return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
 /*
@@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 						u32 value)
 {
-	__omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
+	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+	__omap_dm_timer_write(timer, reg, value, timer->posted);
 }
 
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
 	int c;
 
+	if (!timer->sys_stat)
+		return;
+
 	c = 0;
-	while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
+	while (!(__raw_readl(timer->sys_stat) & 1)) {
 		c++;
 		if (c > 100000) {
 			printk(KERN_ERR "Timer failed to reset\n");
@@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 	if (cpu_class_is_omap2())
 		wakeup = 1;
 
-	__omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
+	__omap_dm_timer_reset(timer, autoidle, wakeup);
 	timer->posted = 1;
 }
 
@@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 	rate = clk_get_rate(timer->fclk);
 #endif
 
-	__omap_dm_timer_stop(timer->io_base, timer->posted, rate);
+	__omap_dm_timer_stop(timer, timer->posted, rate);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 	}
 	l |= OMAP_TIMER_CTRL_ST;
 
-	__omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
+	__omap_dm_timer_load_start(timer, l, load, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 				  unsigned int value)
 {
-	__omap_dm_timer_int_enable(timer->io_base, value);
+	__omap_dm_timer_int_enable(timer, value);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
 	unsigned int l;
 
-	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+	l = __raw_readl(timer->irq_stat);
 
 	return l;
 }
@@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 
 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
-	__omap_dm_timer_write_status(timer->io_base, value);
+	__omap_dm_timer_write_status(timer, value);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-	return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
+	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
@@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void)
 		dm_timer_count = omap4_dm_timer_count;
 		dm_source_names = omap4_dm_source_names;
 		dm_source_clocks = omap4_dm_source_clocks;
+
+		pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
+		return -ENODEV;
 	}
 
 	if (cpu_class_is_omap2())
@@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void)
 		if (sys_timer_reserved & (1  << i)) {
 			timer->reserved = 1;
 			timer->posted = 1;
+			continue;
 		}
 #endif
+		omap_dm_timer_enable(timer);
+		__omap_dm_timer_init_regs(timer);
+		omap_dm_timer_disable(timer);
 	}
 
 	return 0;
arch/arm/plat-omap/include/plat/dmtimer.h +87 -55

224 lines not on this page · raw message

#16 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

[...]

Quoted 9 lines

Well here's what I came up with to deal with the different timer registers. We can't use the context registers as those are for the value naturally..

But we can map the interrupt registers separately and then have the rest start from func_base that is different based on the timer version. Rebasing the rest of the dmtimer hwmod patches on this should be fairly easy, mostly just need to pass timer instead of timer->io_base and use __raw_read/write for the interrupt registers.

I went through the patch. It definitely looks much more simplified now. I will rebase on top of this change.

Quoted 4 lines

Also, I ended up checking the timer revision with if (!(tidr >> 16)) as it seems that those bits are zero for v1 timers? If that works, then we don't need patch 02/12 for the revision number.

Right.
--
Tarun

Quoted 489 lines

Afzal, care to check if that works for AM335X/TI816X/TI814X? It tried it briefly with omap4 gptimer3 as the clockevent and CONFIG_LOCAL_TIMER disabled.

The patch is against the current cleanup branch in linux-omap tree.

Regards,

Tony

From: Tony Lindgren <[email protected]>
Date: Fri, 16 Sep 2011 15:44:20 -0700
Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip

The registers are slightly different between v1 and v2 ip that is available in omap4 and later for some timers.

Add support for v2 ip by mapping the interrupt related registers separately and adding func_base for the functional registers.

Also disable dmtimer driver features on omap4 for now as those need the hwmod conversion series to deal with enabling the timers properly in omap_dm_timer_init.

arch/arm/mach-omap2/timer.c +3 -3
index cf1de7d..21d34fb 100644
@@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 ?{
 ? ? ? ?struct clock_event_device *evt = &clockevent_gpt;
 
- ? ? ? __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+ ? ? ? __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
 ? ? ? ?evt->event_handler(evt);
 ? ? ? ?return IRQ_HANDLED;
@@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = {
 ?static int omap2_gp_timer_set_next_event(unsigned long cycles,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
 ?{
- ? ? ? __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
+ ? ? ? __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - cycles, 1);
 
 ? ? ? ?return 0;
@@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 ?{
 ? ? ? ?u32 period;
 
- ? ? ? __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
+ ? ? ? __omap_dm_timer_stop(&clkev, 1, clkev.rate);
 
 ? ? ? ?switch (mode) {

? ? ? ?case CLOCK_EVT_MODE_PERIODIC:
? ? ? ? ? ? ? ?period = clkev.rate / HZ;
? ? ? ? ? ? ? ?period -= 1;
? ? ? ? ? ? ? ?/* Looks like we need to first set the load value separately */
- ? ? ? ? ? ? ? __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
+ ? ? ? ? ? ? ? __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - period, 1);
- ? ? ? ? ? ? ? __omap_dm_timer_load_start(clkev.io_base,
+ ? ? ? ? ? ? ? __omap_dm_timer_load_start(&clkev,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - period, 1); ? ? ? ? ? ? ? ?break;

arch/arm/mach-omap2/timer.c +7 -6
@@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 ? ? ? ?}
 
 ? ? ? ?omap_hwmod_enable(oh);
+ ? ? ? __omap_dm_timer_init_regs(timer);
 
 ? ? ? ?sys_timer_reserved |= (1 << (gptimer_id - 1));
 
@@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
 ? ? ? ? ? ? ? ? ? ? ? ?clk_put(src);
 ? ? ? ? ? ? ? ?}
 ? ? ? ?}
- ? ? ? __omap_dm_timer_reset(timer->io_base, 1, 1);
+ ? ? ? __omap_dm_timer_reset(timer, 1, 1);
 ? ? ? ?timer->posted = 1;
 
 ? ? ? ?timer->rate = clk_get_rate(timer->fclk);
@@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
 ? ? ? ?omap2_gp_timer_irq.dev_id = (void *)&clkev;
 ? ? ? ?setup_irq(clkev.irq, &omap2_gp_timer_irq);
 
- ? ? ? __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+ ? ? ? __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
 
 ? ? ? ?clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clockevent_gpt.shift);
@@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc;
 ?static DEFINE_CLOCK_DATA(cd);
 ?static cycle_t clocksource_read_cycles(struct clocksource *cs)
 ?{
- ? ? ? return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
+ ? ? ? return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
 ?}
 
 ?static struct clocksource clocksource_gpt = {
@@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void)
 ?{
 ? ? ? ?u32 cyc;
 
- ? ? ? cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+ ? ? ? cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
 ? ? ? ?update_sched_clock(&cd, cyc, (u32)~0);
 ?}
@@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void)
 ? ? ? ?u32 cyc = 0;
 
 ? ? ? ?if (clksrc.reserved)
- ? ? ? ? ? ? ? cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+ ? ? ? ? ? ? ? cyc = __omap_dm_timer_read_counter(&clksrc, 1);
 
 ? ? ? ?return cyc_to_sched_clock(&cd, cyc, (u32)~0);
 ?}
@@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
 ? ? ? ?pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
 ? ? ? ? ? ? ? ?gptimer_id, clksrc.rate);
 
- ? ? ? __omap_dm_timer_load_start(clksrc.io_base,
+ ? ? ? __omap_dm_timer_load_start(&clksrc,
 ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
 ? ? ? ?init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
arch/arm/plat-omap/dmtimer.c +0 -0
index 75a847d..e23b7cf 100644
@@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock;

?*/
?static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) ?{
- ? ? ? return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
+ ? ? ? WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+ ? ? ? return __omap_dm_timer_read(timer, reg, timer->posted);
?}

?/*

arch/arm/plat-omap/dmtimer.c +7 -3
@@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 ?static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 value)
 ?{
- ? ? ? __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
+ ? ? ? WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+ ? ? ? __omap_dm_timer_write(timer, reg, value, timer->posted);
 ?}
 
 ?static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 ?{
 ? ? ? ?int c;
 
+ ? ? ? if (!timer->sys_stat)
+ ? ? ? ? ? ? ? return;
+
 ? ? ? ?c = 0;
- ? ? ? while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
+ ? ? ? while (!(__raw_readl(timer->sys_stat) & 1)) {
 ? ? ? ? ? ? ? ?c++;
 ? ? ? ? ? ? ? ?if (c > 100000) {
 ? ? ? ? ? ? ? ? ? ? ? ?printk(KERN_ERR "Timer failed to reset\n");
@@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 ? ? ? ?if (cpu_class_is_omap2())
 ? ? ? ? ? ? ? ?wakeup = 1;
 
- ? ? ? __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
+ ? ? ? __omap_dm_timer_reset(timer, autoidle, wakeup);
 ? ? ? ?timer->posted = 1;
 ?}
 
@@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 ? ? ? ?rate = clk_get_rate(timer->fclk);

?#endif

- ? ? ? __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
+ ? ? ? __omap_dm_timer_stop(timer, timer->posted, rate); ?}
?EXPORT_SYMBOL_GPL(omap_dm_timer_stop);

arch/arm/plat-omap/dmtimer.c +9 -5
@@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 ? ? ? ?}
 ? ? ? ?l |= OMAP_TIMER_CTRL_ST;
 
- ? ? ? __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
+ ? ? ? __omap_dm_timer_load_start(timer, l, load, timer->posted);
 ?}
 ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 ?void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value)
 ?{
- ? ? ? __omap_dm_timer_int_enable(timer->io_base, value);
+ ? ? ? __omap_dm_timer_int_enable(timer, value);
 ?}
 ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 ?{
 ? ? ? ?unsigned int l;
 
- ? ? ? l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+ ? ? ? l = __raw_readl(timer->irq_stat);
 
 ? ? ? ?return l;
 ?}
@@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 
 ?void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 ?{
- ? ? ? __omap_dm_timer_write_status(timer->io_base, value);
+ ? ? ? __omap_dm_timer_write_status(timer, value);
 ?}
 ?EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 ?unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 ?{
- ? ? ? return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
+ ? ? ? return __omap_dm_timer_read_counter(timer, timer->posted);
 ?}
 ?EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
@@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void)
 ? ? ? ? ? ? ? ?dm_timer_count = omap4_dm_timer_count;
 ? ? ? ? ? ? ? ?dm_source_names = omap4_dm_source_names;
 ? ? ? ? ? ? ? ?dm_source_clocks = omap4_dm_source_clocks;
+
+ ? ? ? ? ? ? ? pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
+ ? ? ? ? ? ? ? return -ENODEV;
 ? ? ? ?}
 
 ? ? ? ?if (cpu_class_is_omap2())
@@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void)
 ? ? ? ? ? ? ? ?if (sys_timer_reserved & (1 ?<< i)) {
 ? ? ? ? ? ? ? ? ? ? ? ?timer->reserved = 1;
 ? ? ? ? ? ? ? ? ? ? ? ?timer->posted = 1;
+ ? ? ? ? ? ? ? ? ? ? ? continue;
 ? ? ? ? ? ? ? ?}

?#endif
+ ? ? ? ? ? ? ? omap_dm_timer_enable(timer);
+ ? ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
+ ? ? ? ? ? ? ? omap_dm_timer_disable(timer);
? ? ? ?}

? ? ? ?return 0;

arch/arm/plat-omap/include/plat/dmtimer.h +0 -0
index eb5d16c..a11d0c0 100644
@@ -98,12 +98,30 @@ int omap_dm_timers_active(void);

?* used by dmtimer.c and sys_timer related code.
?*/

arch/arm/plat-omap/include/plat/dmtimer.h +24 -6
-/* register offsets */
-#define _OMAP_TIMER_ID_OFFSET ? ? ? ? ?0x00
-#define _OMAP_TIMER_OCP_CFG_OFFSET ? ? 0x10
-#define _OMAP_TIMER_SYS_STAT_OFFSET ? ?0x14
-#define _OMAP_TIMER_STAT_OFFSET ? ? ? ? ? ? ? ?0x18
-#define _OMAP_TIMER_INT_EN_OFFSET ? ? ?0x1c
+/*
+ * The interrupt registers are different between v1 and v2 ip.
+ * These registers are offsets from timer->iobase.
+ */
+#define OMAP_TIMER_ID_OFFSET ? ? ? ? ? 0x00
+#define OMAP_TIMER_OCP_CFG_OFFSET ? ? ?0x10
+
+#define OMAP_TIMER_V1_SYS_STAT_OFFSET ?0x14
+#define OMAP_TIMER_V1_STAT_OFFSET ? ? ?0x18
+#define OMAP_TIMER_V1_INT_EN_OFFSET ? ?0x1c
+
+#define OMAP_TIMER_V2_IRQSTATUS_RAW ? ?0x24
+#define OMAP_TIMER_V2_IRQSTATUS ? ? ? ? ? ? ? ?0x28
+#define OMAP_TIMER_V2_IRQENABLE_SET ? ?0x2c
+#define OMAP_TIMER_V2_IRQENABLE_CLR ? ?0x30
+
+/*
+ * The functional registers have a different base on v1 and v2 ip.
+ * These registers are offsets from timer->func_base. The func_base
+ * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
+ *
+ */
+#define OMAP_TIMER_V2_FUNC_OFFSET ? ? ? ? ? ? ?0x14
+

?#define _OMAP_TIMER_WAKEUP_EN_OFFSET ? 0x20
?#define _OMAP_TIMER_CTRL_OFFSET ? ? ? ? ? ? ? ?0x24 ?#define ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_GPOCFG ? ? ? ? ?(1 << 14)

arch/arm/plat-omap/include/plat/dmtimer.h +0 -0
@@ -147,21 +165,6 @@ int omap_dm_timers_active(void);

?/* register offsets with the write pending bit encoded */ ?#define ? ? ? ?WPSHIFT ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 16

arch/arm/plat-omap/include/plat/dmtimer.h +0 -15
-#define OMAP_TIMER_ID_REG ? ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_ID_OFFSET \
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_OCP_CFG_REG ? ? ? ? ? ? ? ? (_OMAP_TIMER_OCP_CFG_OFFSET \
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_SYS_STAT_REG ? ? ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_SYS_STAT_OFFSET \
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_STAT_REG ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_STAT_OFFSET \
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_INT_EN_REG ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_INT_EN_OFFSET \
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
-

?#define OMAP_TIMER_WAKEUP_EN_REG ? ? ? ? ? ? ? (_OMAP_TIMER_WAKEUP_EN_OFFSET \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (WP_NONE << WPSHIFT))

arch/arm/plat-omap/include/plat/dmtimer.h +0 -0
@@ -213,7 +216,14 @@ struct omap_dm_timer {

?#ifdef CONFIG_ARCH_OMAP2PLUS
? ? ? ?struct clk *iclk, *fclk;
?#endif
- ? ? ? void __iomem *io_base;
+ ? ? ? void __iomem ? ?*io_base;
+ ? ? ? void __iomem ? ?*sys_stat; ? ? ?/* TISTAT timer status */
+ ? ? ? void __iomem ? ?*irq_stat; ? ? ?/* TISR/IRQSTATUS interrupt status */
+ ? ? ? void __iomem ? ?*irq_ena; ? ? ? /* irq enable */
+ ? ? ? void __iomem ? ?*irq_dis; ? ? ? /* irq disable, only on v2 ip */
+ ? ? ? void __iomem ? ?*pend; ? ? ? ? ?/* write pending */
+ ? ? ? void __iomem ? ?*func_base; ? ? /* function register base */ +
? ? ? ?unsigned long rate;
? ? ? ?unsigned reserved:1;
? ? ? ?unsigned enabled:1;

arch/arm/plat-omap/include/plat/dmtimer.h +31 -9
@@ -223,35 +233,57 @@ struct omap_dm_timer {
 ?extern u32 sys_timer_reserved;
 ?void omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
-static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
+static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int posted)
 ?{
 ? ? ? ?if (posted)
- ? ? ? ? ? ? ? while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? & (reg >> WPSHIFT))
+ ? ? ? ? ? ? ? while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 ? ? ? ? ? ? ? ? ? ? ? ?cpu_relax();
 
- ? ? ? return __raw_readl(base + (reg & 0xff));
+ ? ? ? return __raw_readl(timer->func_base + (reg & 0xff));
 ?}
 
-static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)
+static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 reg, u32 val, int posted)
 ?{
 ? ? ? ?if (posted)
- ? ? ? ? ? ? ? while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? & (reg >> WPSHIFT))
+ ? ? ? ? ? ? ? while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 ? ? ? ? ? ? ? ? ? ? ? ?cpu_relax();
 
- ? ? ? __raw_writel(val, base + (reg & 0xff));
+ ? ? ? __raw_writel(val, timer->func_base + (reg & 0xff));
+}
+
+static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
+{
+ ? ? ? u32 tidr;
+
+ ? ? ? /* Assume v1 ip if bits [31:16] are zero */
+ ? ? ? tidr = __raw_readl(timer->io_base);
+ ? ? ? if (!(tidr >> 16)) {
+ ? ? ? ? ? ? ? timer->sys_stat = timer->io_base + OMAP_TIMER_V1_SYS_STAT_OFFSET;
+ ? ? ? ? ? ? ? timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
+ ? ? ? ? ? ? ? timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
+ ? ? ? ? ? ? ? timer->irq_dis = 0;
+ ? ? ? ? ? ? ? timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
+ ? ? ? ? ? ? ? timer->func_base = timer->io_base;
+ ? ? ? } else {
+ ? ? ? ? ? ? ? timer->sys_stat = 0;
+ ? ? ? ? ? ? ? timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
+ ? ? ? ? ? ? ? timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
+ ? ? ? ? ? ? ? timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
+ ? ? ? ? ? ? ? timer->pend = timer->io_base +
+ ? ? ? ? ? ? ? ? ? ? ? _OMAP_TIMER_WRITE_PEND_OFFSET + OMAP_TIMER_V2_FUNC_OFFSET;
+ ? ? ? ? ? ? ? timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
+ ? ? ? }
 ?}
 

?/* Assumes the source clock has been set by caller */

arch/arm/plat-omap/include/plat/dmtimer.h +2 -2
-static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int wakeup)
+static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int autoidle, int wakeup)

?{
? ? ? ?u32 l;

- ? ? ? l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0);
+ ? ? ? l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); ? ? ? ?l |= 0x02 << 3; ?/* Set to smart-idle mode */
? ? ? ?l |= 0x2 << 8; ? /* Set clock activity to perserve f-clock on idle */

arch/arm/plat-omap/include/plat/dmtimer.h +1 -1
@@ -261,10 +293,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
 ? ? ? ?if (wakeup)
 ? ? ? ? ? ? ? ?l |= 1 << 2;
 
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0);
+ ? ? ? __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
 

? ? ? ?/* Match hardware reset default of posted mode */
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG,
+ ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_POSTED, 0); ?}

arch/arm/plat-omap/include/plat/dmtimer.h +4 -4
@@ -286,18 +318,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
 ? ? ? ?return ret;
 ?}
 
-static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long rate)
+static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted, unsigned long rate)
 ?{
 ? ? ? ?u32 l;
 
- ? ? ? l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+ ? ? ? l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
 ? ? ? ?if (l & OMAP_TIMER_CTRL_ST) {
 ? ? ? ? ? ? ? ?l &= ~0x1;
- ? ? ? ? ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted);
+ ? ? ? ? ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);

?#ifdef CONFIG_ARCH_OMAP2PLUS
? ? ? ? ? ? ? ?/* Readback to make sure write has completed */
- ? ? ? ? ? ? ? __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+ ? ? ? ? ? ? ? __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); ? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ? * Wait for functional clock period x 3.5 to make sure that ? ? ? ? ? ? ? ? * timer is stopped

arch/arm/plat-omap/include/plat/dmtimer.h +0 -0
@@ -307,34 +339,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
 ? ? ? ?}
 

? ? ? ?/* Ack possibly pending interrupt */
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_TIMER_INT_OVERFLOW, 0);
+ ? ? ? __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat); ?}

arch/arm/plat-omap/include/plat/dmtimer.h +3 -2
-static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int load, int posted)
+static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 ctrl, unsigned int load,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)

?{
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted);
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted);
+ ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
+ ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted); ?}

arch/arm/plat-omap/include/plat/dmtimer.h +1 -1
-static inline void __omap_dm_timer_int_enable(void __iomem *base,
+static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value) ?{
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0);
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
+ ? ? ? __raw_writel(value, timer->irq_ena);
+ ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0); ?}

arch/arm/plat-omap/include/plat/dmtimer.h +2 -2
-static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)
+static inline unsigned int
+__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)

?{
- ? ? ? return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted);
+ ? ? ? return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted); ?}

arch/arm/plat-omap/include/plat/dmtimer.h +1 -1
-static inline void __omap_dm_timer_write_status(void __iomem *base,
+static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value) ?{
- ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0);
+ ? ? ? __raw_writel(value, timer->irq_stat);
?}

?#endif /* __ASM_ARCH_DMTIMER_H */

maintainer
#17 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

Quoted 8 lines · DebBarma, Tarun Kanti
Quoted 6 lines

But we can map the interrupt registers separately and then have the rest start from func_base that is different based on the timer version. Rebasing the rest of the dmtimer hwmod patches on this should be fairly easy, mostly just need to pass timer instead of timer->io_base and use __raw_read/write for the interrupt registers.

I went through the patch. It definitely looks much more simplified now. I will rebase on top of this change.

OK thanks, can I add your Acked-by then?

Tony

#18 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

In reply to Tony Lindgren

Tony Lindgren wrote on Saturday, September 17, 2011 7:06 AM:

Quoted 12 lines

device driver)

Quoted 1 line · DebBarma, Tarun Kanti

[...]

Afzal, care to check if that works for AM335X/TI816X/TI814X? It tried it briefly with omap4 gptimer3 as the clockevent and CONFIG_LOCAL_TIMER disabled.

The patch is against the current cleanup branch in linux-omap tree.

Quoted 9 lines

Regards,

Tony

From: Tony Lindgren <[email protected]>
Date: Fri, 16 Sep 2011 15:44:20 -0700
Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip

[...]

Tony,
Kernel boots fine on TI816X (should also boot on TI814X) with your patch and patches (including OSC clock fix) from series
http://www.spinics.net/lists/linux-omap/msg57011.html

Thanks.

Hemant

maintainer
#19 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

Quoted 5 lines · Pedanekar, Hemant

Tony,
Kernel boots fine on TI816X (should also boot on TI814X) with your patch and patches (including OSC clock fix) from series
http://www.spinics.net/lists/linux-omap/msg57011.html

OK good to hear, I assume I can add your Tested-by then?

Regards,

Tony

#20 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

Tony Lindgren wrote on Monday, September 19, 2011 11:11 PM:

Quoted 9 lines

device driver)

Quoted 5 lines · Pedanekar, Hemant

Tony,
Kernel boots fine on TI816X (should also boot on TI814X) with your patch and patches (including OSC clock fix) from series
http://www.spinics.net/lists/linux-omap/msg57011.html

Quoted 5 lines

OK good to hear, I assume I can add your Tested-by then?

Regards,

Tony

Yes.

Thanks.

Hemant

#21 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

In reply to Tony Lindgren

Hi Tony,

Quoted 2 lines · Tony Lindgren

Afzal, care to check if that works for AM335X/TI816X/TI814X?

With following patch over yours, AM335X (the only board with me) boots up fine.

Regards
Afzal

Quoted 1 line

From ff64a239e60f9b517860eb2fe9c4f88a188ca51d Mon Sep 17 00:00:00 2001

From: Afzal Mohammed <[email protected]>
Date: Mon, 19 Sep 2011 10:06:59 +0530
Subject: [PATCH] ARM: OMAP: dmtimer register safe access

Access dmtimer registers after setting it's parent clock. If default parent is not physically present, accessing register causes abort, so access registers after proper parent is set.

---
 arch/arm/mach-omap2/timer.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/timer.c +1 -1
index 1746c69..ababc4d 100644
@@ -172,7 +172,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
        }
 
        omap_hwmod_enable(oh);
-       __omap_dm_timer_init_regs(timer);
 
        sys_timer_reserved |= (1 << (gptimer_id - 1));
 
@@ -190,6 +189,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                        clk_put(src);
                }
        }
+       __omap_dm_timer_init_regs(timer);
        __omap_dm_timer_reset(timer, 1, 1);
        timer->posted = 1;
 

--
1.6.2.4

maintainer
#22 lore raw

PATCH 1/1 ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)

Quoted 7 lines · Mohammed, Afzal

Hi Tony,

Quoted 2 lines · Tony Lindgren

Afzal, care to check if that works for AM335X/TI816X/TI814X?

With following patch over yours, AM335X (the only board with me) boots up fine.

Thanks for catching that, will fold it in with your Signed-off-by.

Regards,

Tony

#23 lore raw

PATCH v15 7/12 OMAP: dmtimer: pm_runtime support

In reply to Tarun Kanti DebBarma

Add pm_runtime feature to dmtimer whereby *_runtime_get_sync() is called within omap_dm_timer_enable(), pm_runtime_put() is called in omap_dm_timer_disable(). In addition to calling pm_runtime_enable, we are calling pm_runtime_irq_safe so that they can be called from interrupt context.

---
 arch/arm/plat-omap/dmtimer.c              |   33 ++++++++--------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |    1 -
 2 files changed, 10 insertions(+), 24 deletions(-)
arch/arm/plat-omap/dmtimer.c +10 -23
index 854e735..39751f9 100644
@@ -38,6 +38,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/dmtimer.h>
 
@@ -209,33 +210,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_free);
 
 void omap_dm_timer_enable(struct omap_dm_timer *timer)
 {
-	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
-
-	if (timer->enabled)
-		return;
-
-	if (!pdata->needs_manual_reset) {
-		clk_enable(timer->fclk);
-		clk_enable(timer->iclk);
-	}
-
-	timer->enabled = 1;
+	pm_runtime_get_sync(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 
 void omap_dm_timer_disable(struct omap_dm_timer *timer)
 {
-	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
-
-	if (!timer->enabled)
-		return;
-
-	if (!pdata->needs_manual_reset) {
-		clk_disable(timer->iclk);
-		clk_disable(timer->fclk);
-	}
-
-	timer->enabled = 0;
+	pm_runtime_put(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 
@@ -475,7 +456,7 @@ int omap_dm_timers_active(void)
 	struct omap_dm_timer *timer;
 
 	list_for_each_entry(timer, &omap_timer_list, node) {
-		if (!timer->enabled)
+		if (!timer->reserved)
 			continue;
 
 		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
@@ -550,6 +531,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->pdev = pdev;
 
+	/* Skip pm_runtime_enable for OMAP1 */
+	if (!pdata->needs_manual_reset) {
+		pm_runtime_enable(&pdev->dev);
+		pm_runtime_irq_safe(&pdev->dev);
+	}
+
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
arch/arm/plat-omap/include/plat/dmtimer.h +0 -1
index fc086ce..5368140 100644
@@ -239,7 +239,6 @@ struct omap_dm_timer {
 	void __iomem *io_base;
 	unsigned long rate;
 	unsigned reserved:1;
-	unsigned enabled:1;
 	unsigned posted:1;
 	u8 func_offset;
 	u8 intr_offset;
Signature · 1 line
1.7.0.4
#24 lore raw

PATCH v15 8/12 OMAP: dmtimer: add timeout to low-level routines

In reply to Tarun Kanti DebBarma

The low-level read and write access routines wait on write-pending register in posted mode to make sure that previous write is complete on respective registers. This waiting is done in an infinite while loop. Now it is being modified to use timeout instead.

---
 arch/arm/plat-omap/include/plat/dmtimer.h |   35 ++++++++++++++++++++--------
 1 files changed, 25 insertions(+), 10 deletions(-)
arch/arm/plat-omap/include/plat/dmtimer.h +25 -10
index 5368140..41723f4 100644
@@ -37,6 +37,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <plat/common.h>
+
 #ifndef __ASM_ARCH_DMTIMER_H
 #define __ASM_ARCH_DMTIMER_H
 
@@ -231,6 +233,9 @@ int omap_dm_timers_active(void);
 #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG				\
 		(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
 
+/* 10ms timeout delay */
+#define MAX_WRITE_PEND_WAIT            10000
+
 struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
@@ -252,11 +257,16 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
 						int posted, u8 func_offset)
 {
-	if (posted)
-		while (__raw_readl(base +
-			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff))
-				& (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(base +
+			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff)) &
+				(reg >> WPSHIFT)), MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
+			pr_err("read timeout.\n");
+	}
 
 	return __raw_readl(base + (reg & 0xff));
 }
@@ -264,11 +274,16 @@ static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
 static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
 						int posted, u8 func_offset)
 {
-	if (posted)
-		while (__raw_readl(base +
-			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff))
-				& (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(base +
+			((OMAP_TIMER_WRITE_PEND_REG + func_offset) & 0xff)) &
+				(reg >> WPSHIFT)), MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON(i == MAX_WRITE_PEND_WAIT))
+			pr_err("write timeout.\n");
+	}
 
 	__raw_writel(val, base + (reg & 0xff));
 }
Signature · 1 line
1.7.0.4
#25 lore raw

PATCH v15 9/12 OMAP: dmtimer: mark clocksource and clockevent timers reserved

In reply to Tarun Kanti DebBarma

In driver probe use sys_timer_reserved to identify which all timers have already been used for clocksource and clockevent. Mark all those timers as reserved so that no one else can use them.

---
 arch/arm/plat-omap/dmtimer.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)
arch/arm/plat-omap/dmtimer.c +11 -6
index 39751f9..6312dfb 100644
@@ -531,12 +531,17 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->pdev = pdev;
 
-	/* Skip pm_runtime_enable for OMAP1 */
-	if (!pdata->needs_manual_reset) {
-		pm_runtime_enable(&pdev->dev);
-		pm_runtime_irq_safe(&pdev->dev);
-	}
-
+/*
+ * sys_timer_reserved is not defined for OMAP1.
+ * Use the macro to avoid compilation error on OMAP1.
+ */
+#if defined(CONFIG_ARCH_OMAP2PLUS)
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_irq_safe(&pdev->dev);
+	/* Mark clocksource and clockevent timers as reserved */
+	if ((sys_timer_reserved >> (pdev->id - 1)) & 0x1)
+		timer->reserved = 1;
+#endif
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
Signature · 1 line
1.7.0.4
#26 lore raw

PATCH v15 10/12 OMAP: dmtimer: low-power mode support

In reply to Tarun Kanti DebBarma

Clock is enabled only when timer is started and disabled when the the timer is stopped. Therefore before accessing registers in functions clock is enabled and then disabled back at the end of access. Context save is done dynamically whenever the registers are modified. Context restore is called when context is lost.

---
 arch/arm/mach-omap2/timer.c               |   10 ++-
 arch/arm/plat-omap/dmtimer.c              |  128 +++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/dmtimer.h |   31 +++++++
 3 files changed, 163 insertions(+), 6 deletions(-)
arch/arm/mach-omap2/timer.c +9 -1
index 4758d3e..984a677 100644
@@ -44,6 +44,9 @@
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -444,6 +447,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	struct dmtimer_platform_data *pdata;
 	struct omap_device *od;
 	struct omap_timer_capability_dev_attr *timer_dev_attr;
+	struct powerdomain *pwrdm;
 
 	pr_debug("%s: %s\n", __func__, oh->name);
 
@@ -473,7 +477,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 
 	pdata->set_timer_src = omap2_dm_timer_set_src;
 	pdata->timer_ip_type = oh->class->rev;
-
+	pwrdm = omap_hwmod_get_pwrdm(oh);
+	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+#ifdef CONFIG_PM
+	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+#endif
 	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
 			omap2_dmtimer_latency,
 			ARRAY_SIZE(omap2_dmtimer_latency),
arch/arm/plat-omap/dmtimer.c +123 -5

286 lines not on this page · raw message

arch/arm/plat-omap/include/plat/dmtimer.h +31 -0
index 41723f4..8c0fbb6 100644
@@ -86,6 +86,9 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_type;
 	u32 needs_manual_reset:1;
+	bool loses_context;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -236,6 +239,29 @@ int omap_dm_timers_active(void);
 /* 10ms timeout delay */
 #define MAX_WRITE_PEND_WAIT            10000
 
+struct timer_regs {
+	u32 tidr;
+	u32 tiocp_cfg;
+	u32 tistat;
+	u32 tisr;
+	u32 tier;
+	u32 twer;
+	u32 tclr;
+	u32 tcrr;
+	u32 tldr;
+	u32 ttrg;
+	u32 twps;
+	u32 tmar;
+	u32 tcar1;
+	u32 tsicr;
+	u32 tcar2;
+	u32 tpir;
+	u32 tnir;
+	u32 tcvr;
+	u32 tocr;
+	u32 towr;
+};
+
 struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
@@ -247,8 +273,13 @@ struct omap_dm_timer {
 	unsigned posted:1;
 	u8 func_offset;
 	u8 intr_offset;
+	struct timer_regs context;
+	bool loses_context;
+	int ctx_loss_count;
 	struct platform_device *pdev;
 	struct list_head node;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 extern u32 sys_timer_reserved;
Signature · 1 line
1.7.0.4
#27 lore raw

PATCH v15 11/12 OMAP: dmtimer: extend spinlock to exported APIs

In reply to Tarun Kanti DebBarma

Since the exported APIs can be called from interrupt context extend spinlock protection to some more relevant APIs to avoid race condition.

---
 arch/arm/plat-omap/dmtimer.c |   34 +++++++++++++++++++++++++++++++---
 1 files changed, 31 insertions(+), 3 deletions(-)
arch/arm/plat-omap/dmtimer.c +31 -3
index 15fe01a..8891f80 100644
@@ -174,7 +174,6 @@ struct omap_dm_timer *omap_dm_timer_request(void)
 		timer->reserved = 1;
 		break;
 	}
-	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (timer) {
 		ret = omap_dm_timer_prepare(timer);
@@ -183,6 +182,7 @@ struct omap_dm_timer *omap_dm_timer_request(void)
 			timer = NULL;
 		}
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (!timer)
 		pr_debug("%s: timer request failed!\n", __func__);
@@ -205,7 +205,6 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (timer) {
 		ret = omap_dm_timer_prepare(timer);
@@ -214,6 +213,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 			timer = NULL;
 		}
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (!timer)
 		pr_debug("%s: timer%d request failed!\n", __func__, id);
@@ -317,9 +317,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (timer->loses_context) {
 		u32 ctx_loss_cnt_after =
 			timer->get_context_loss_count(&timer->pdev->dev);
@@ -335,15 +337,17 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 
 	/* Save the context */
 	timer->context.tclr = l;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
-	unsigned long rate = 0;
+	unsigned long rate = 0, flags;
 	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 	bool is_omap2 = true;
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (pdata->needs_manual_reset)
 		is_omap2 = false;
 	else
@@ -367,6 +371,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	timer->context.tisr =
 			omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
@@ -389,8 +394,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int load)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -403,6 +410,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	/* Save the context */
 	timer->context.tclr = l;
 	timer->context.tldr = load;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
@@ -412,9 +420,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
                             unsigned int load)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (timer->loses_context) {
 		u32 ctx_loss_cnt_after =
 			timer->get_context_loss_count(&timer->pdev->dev);
@@ -438,6 +448,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tclr = l;
 	timer->context.tldr = load;
 	timer->context.tcrr = load;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -445,8 +456,10 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 			     unsigned int match)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -458,6 +471,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	/* Save the context */
 	timer->context.tclr = l;
 	timer->context.tmar = match;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
@@ -466,8 +480,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 			   int toggle, int trigger)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
 	       OMAP_TIMER_CTRL_PT | (0x03 << 10));
@@ -480,6 +496,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 
 	/* Save the context */
 	timer->context.tclr = l;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
@@ -487,8 +504,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -499,6 +518,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 
 	/* Save the context */
 	timer->context.tclr = l;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
@@ -506,13 +526,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 				  unsigned int value)
 {
+	unsigned long flags;
+
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	__omap_dm_timer_int_enable(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
 
 	/* Save the context */
 	timer->context.tier = value;
 	timer->context.twer = value;
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
@@ -570,16 +594,20 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 int omap_dm_timers_active(void)
 {
 	struct omap_dm_timer *timer;
+	unsigned long flags;
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_for_each_entry(timer, &omap_timer_list, node) {
 		if (!timer->reserved)
 			continue;
 
 		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
 		    OMAP_TIMER_CTRL_ST) {
+			spin_unlock_irqrestore(&dm_timer_lock, flags);
 			return 1;
 		}
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
Signature · 1 line
1.7.0.4
maintainer
#28 lore raw

PATCH v15 11/12 OMAP: dmtimer: extend spinlock to exported APIs

Quoted 3 lines · Tarun Kanti DebBarma

Since the exported APIs can be called from interrupt context extend spinlock protection to some more relevant APIs to avoid race condition.

We should have locking for requesting and releasing a timer etc, but I don't see need for that for the timer specific functions.

arch/arm/plat-omap/dmtimer.c EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); · line 327

Quoted 12 lines
arch/arm/plat-omap/dmtimer.c +2 -0
@@ -317,9 +317,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (timer->loses_context) {
 		u32 ctx_loss_cnt_after =
 			timer->get_context_loss_count(&timer->pdev->dev);

Here the caller already owns the timer being started. So there should never be multiple users for a single timer. If there are, then the caller should take care of locking.

arch/arm/plat-omap/dmtimer.c void omap_dm_timer_start(struct omap_dm_timer *timer) · line 353

Quoted 11 lines

void omap_dm_timer_stop(struct omap_dm_timer *timer) {

arch/arm/plat-omap/dmtimer.c +2 -1
-	unsigned long rate = 0;
+	unsigned long rate = 0, flags;
 	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 	bool is_omap2 = true;
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (pdata->needs_manual_reset)
 		is_omap2 = false;
 	else

Here too.

arch/arm/plat-omap/dmtimer.c void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, · line 403

Quoted 11 lines
arch/arm/plat-omap/dmtimer.c +2 -0
@@ -389,8 +394,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int load)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;

And here.

arch/arm/plat-omap/dmtimer.c void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, · line 430

Quoted 12 lines
arch/arm/plat-omap/dmtimer.c +2 -0
@@ -412,9 +420,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
                             unsigned int load)
 {
 	u32 l;
+	unsigned long flags;
 
 	omap_dm_timer_enable(timer);
 
+	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (timer->loses_context) {
 		u32 ctx_loss_cnt_after =
 			timer->get_context_loss_count(&timer->pdev->dev);

Not needed here either. And that's the case for all the other functions too.

Regards,

Tony

#29 lore raw

PATCH v15 11/12 OMAP: dmtimer: extend spinlock to exported APIs

Quoted 7 lines · Tony Lindgren
Quoted 3 lines · Tarun Kanti DebBarma

Since the exported APIs can be called from interrupt context extend spinlock protection to some more relevant APIs to avoid race condition.

We should have locking for requesting and releasing a timer etc, but I don't see need for that for the timer specific functions.

Alright... I will remove locking from timer specific functions. In that case we have extension of locks to just following two functions:
omap_dm_timer_request()
omap_dm_timer_request_specific()

So, I can modify the patch subject and description accordingly.

Quoted 9 lines
Quoted 9 lines
(quoted diff) +1 -0
@@ -317,9 +317,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 ?void omap_dm_timer_start(struct omap_dm_timer *timer)
 ?{
 ? ? ? u32 l;
+ ? ? unsigned long flags;
 
 ? ? ? omap_dm_timer_enable(timer);
 
Quoted 8 lines
Quoted 4 lines
(quoted diff) +1 -0
+ ? ? spin_lock_irqsave(&dm_timer_lock, flags);
 ? ? ? if (timer->loses_context) {

? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);

Here the caller already owns the timer being started. So there should never be multiple users for a single timer. If there are, then the caller should take care of locking.

Ok.

Quoted 8 lines
Quoted 8 lines

?void omap_dm_timer_stop(struct omap_dm_timer *timer)
?{
- ? ? unsigned long rate = 0;
+ ? ? unsigned long rate = 0, flags;
? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; ? ? ? bool is_omap2 = true;

Quoted 6 lines
Quoted 4 lines

+ ? ? spin_lock_irqsave(&dm_timer_lock, flags);
? ? ? if (pdata->needs_manual_reset)
? ? ? ? ? ? ? is_omap2 = false;
? ? ? else

Here too.

Right.

Quoted 7 lines
Quoted 7 lines
(quoted diff) +1 -0
@@ -389,8 +394,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int load)
 ?{
 ? ? ? u32 l;
+ ? ? unsigned long flags;
 
Quoted 7 lines

Review void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, · line 403

Quoted 5 lines
(quoted diff) +1 -0
 ? ? ? omap_dm_timer_enable(timer);
+ ? ? spin_lock_irqsave(&dm_timer_lock, flags);
 ? ? ? l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 ? ? ? if (autoreload)
 ? ? ? ? ? ? ? l |= OMAP_TIMER_CTRL_AR;

And here.

Ok.

Quoted 9 lines
Quoted 9 lines
(quoted diff) +1 -0
@@ -412,9 +420,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int load)
 ?{
 ? ? ? u32 l;
+ ? ? unsigned long flags;
 
 ? ? ? omap_dm_timer_enable(timer);
 
Quoted 7 lines
Quoted 4 lines
(quoted diff) +1 -0
+ ? ? spin_lock_irqsave(&dm_timer_lock, flags);
 ? ? ? if (timer->loses_context) {

? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);

Not needed here either. And that's the case for all the other functions too.

Sure.
--
Tarun

Quoted 5 lines

Regards,

Tony

#30 lore raw

PATCH v15 12/12 OMAP: dmtimer: add error handling to export APIs

In reply to Tarun Kanti DebBarma

Add error handling code to exported APIs. Currently, the APIs assume they are operating on valid parameters passed to it.

---
 arch/arm/plat-omap/dmtimer.c              |  101 ++++++++++++++++++++++-------
 arch/arm/plat-omap/include/plat/dmtimer.h |   24 ++++----
 2 files changed, 88 insertions(+), 37 deletions(-)
arch/arm/plat-omap/dmtimer.c +76 -25
index a793482..34db29b 100644
@@ -222,12 +222,16 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
-void omap_dm_timer_free(struct omap_dm_timer *timer)
+int omap_dm_timer_free(struct omap_dm_timer *timer)
 {
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
 	timer->reserved = 0;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_free);
 
@@ -245,7 +249,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 
 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
 {
-	return timer->irq;
+	if (timer)
+		return timer->irq;
+	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
 
@@ -289,7 +295,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
-	return timer->fclk;
+	if (timer)
+		return timer->fclk;
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
 
@@ -303,22 +311,26 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 #endif
 
-void omap_dm_timer_trigger(struct omap_dm_timer *timer)
+int omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
-	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
-		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
-		return;
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer not available or enabled.\n", __func__);
+		return -EINVAL;
 	}
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 
-void omap_dm_timer_start(struct omap_dm_timer *timer)
+int omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -338,15 +350,19 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 	/* Save the context */
 	timer->context.tclr = l;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
-void omap_dm_timer_stop(struct omap_dm_timer *timer)
+int omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0, flags;
 	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 	bool is_omap2 = true;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	if (pdata->needs_manual_reset)
 		is_omap2 = false;
@@ -373,13 +389,19 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 			omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
 	int ret;
-	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	struct dmtimer_platform_data *pdata;
+
+	if (unlikely(!timer))
+		return -EINVAL;
+
+	pdata = timer->pdev->dev.platform_data;
 
 	if (source < 0 || source >= 3)
 		return -EINVAL;
@@ -390,12 +412,15 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
-void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int load)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
@@ -413,16 +438,20 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tldr = load;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
 /* Optimized set_load which removes costly spin wait in timer_start */
-void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
+int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
                             unsigned int load)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -450,15 +479,19 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tldr = load;
 	timer->context.tcrr = load;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
-void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
+int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 			     unsigned int match)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
@@ -474,15 +507,19 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	timer->context.tmar = match;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
-void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
+int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 			   int toggle, int trigger)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
@@ -499,14 +536,18 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 	timer->context.tclr = l;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
-void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
+int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
@@ -521,14 +562,18 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 	timer->context.tclr = l;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 
-void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 				  unsigned int value)
 {
 	unsigned long flags;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	__omap_dm_timer_int_enable(timer->io_base, value,
@@ -539,6 +584,7 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 	timer->context.twer = value;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -546,8 +592,8 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
 	unsigned int l;
 
-	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
-		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer not available or enabled.\n", __func__);
 		return 0;
 	}
 
@@ -557,19 +603,23 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 
-void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
+		return -EINVAL;
+
 	__omap_dm_timer_write_status(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
 	/* Save the context */
 	timer->context.tisr = value;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
-		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer not iavailable or enabled.\n", __func__);
 		return 0;
 	}
 
@@ -578,17 +628,18 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
-void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
+int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
-	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
-		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
-		return;
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer not available or enabled.\n", __func__);
+		return -EINVAL;
 	}
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
 
 	/* Save the context */
 	timer->context.tcrr = value;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
arch/arm/plat-omap/include/plat/dmtimer.h +12 -12
index 8c0fbb6..110a649 100644
@@ -93,7 +93,7 @@ struct dmtimer_platform_data {
 
 struct omap_dm_timer *omap_dm_timer_request(void);
 struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
-void omap_dm_timer_free(struct omap_dm_timer *timer);
+int omap_dm_timer_free(struct omap_dm_timer *timer);
 void omap_dm_timer_enable(struct omap_dm_timer *timer);
 void omap_dm_timer_disable(struct omap_dm_timer *timer);
 
@@ -102,23 +102,23 @@ int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
 u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
 
-void omap_dm_timer_trigger(struct omap_dm_timer *timer);
-void omap_dm_timer_start(struct omap_dm_timer *timer);
-void omap_dm_timer_stop(struct omap_dm_timer *timer);
+int omap_dm_timer_trigger(struct omap_dm_timer *timer);
+int omap_dm_timer_start(struct omap_dm_timer *timer);
+int omap_dm_timer_stop(struct omap_dm_timer *timer);
 
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
-void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
-void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
-void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
+int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
+int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
+int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
+int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
+int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
 
-void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
 
 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
-void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
-void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
+int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
 
 int omap_dm_timers_active(void);
 
Signature · 1 line
1.7.0.4