All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-20 11:30 ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma

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://github.com/tmlind/linux.git
Branch: cleanup

Test Info:
- OMAP4430SDP: Functional tests.
- OMAP3430SDP: Functional. Off-mode does not work.
- OMAP2430SDP: Functional tests.
- OMAP2420SDP: Functional tests.
- OMAP1710SDP: Boot test.

v16:
(1) Baselined on top of Tony Lindgren's following patch:
    ARM: OMAP: Add support for dmtimer v2 ip
(2) Removed usage of ip version constants from dmtimer files
    as well as hwmod database.
(3) Use __omap_dm_timer_init_regs() to initialize timer base
    and offsets for both old and new ip versions in probe().
(4) Added "tidr" register field in omap_dm_timer{} which is
    is initialized with TIDR register value during probe.
    This is used in context restore function to differentiate
    ip version. This avoids reading the TIDR register whenever
    context restore function is called.

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 <toddpoynor@google.com> implemented
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg52677.html
http://www.mail-archive.com/linux-omap@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
  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: do remaining initialization in probe
  OMAP: dmtimer: low-power mode support
  OMAP: dmtimer: extend spinlock in request functions
  OMAP: dmtimer: add error handling to export APIs
  OMAP: dmtimer: get rid of timer_ip_version field

 arch/arm/mach-omap1/Makefile                       |    2 +-
 arch/arm/mach-omap1/timer.c                        |  173 +++++
 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_2xxx_ipblock_data.c |    1 -
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |   29 +-
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |   22 +
 arch/arm/mach-omap2/timer.c                        |  169 +++++-
 arch/arm/plat-omap/dmtimer.c                       |  719 ++++++++++++--------
 arch/arm/plat-omap/include/plat/dmtimer.h          |  137 +++-
 14 files changed, 1120 insertions(+), 341 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-20 11:30 ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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://github.com/tmlind/linux.git
Branch: cleanup

Test Info:
- OMAP4430SDP: Functional tests.
- OMAP3430SDP: Functional. Off-mode does not work.
- OMAP2430SDP: Functional tests.
- OMAP2420SDP: Functional tests.
- OMAP1710SDP: Boot test.

v16:
(1) Baselined on top of Tony Lindgren's following patch:
    ARM: OMAP: Add support for dmtimer v2 ip
(2) Removed usage of ip version constants from dmtimer files
    as well as hwmod database.
(3) Use __omap_dm_timer_init_regs() to initialize timer base
    and offsets for both old and new ip versions in probe().
(4) Added "tidr" register field in omap_dm_timer{} which is
    is initialized with TIDR register value during probe.
    This is used in context restore function to differentiate
    ip version. This avoids reading the TIDR register whenever
    context restore function is called.

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 <toddpoynor@google.com> 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
  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: do remaining initialization in probe
  OMAP: dmtimer: low-power mode support
  OMAP: dmtimer: extend spinlock in request functions
  OMAP: dmtimer: add error handling to export APIs
  OMAP: dmtimer: get rid of timer_ip_version field

 arch/arm/mach-omap1/Makefile                       |    2 +-
 arch/arm/mach-omap1/timer.c                        |  173 +++++
 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_2xxx_ipblock_data.c |    1 -
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |   29 +-
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |   22 +
 arch/arm/mach-omap2/timer.c                        |  169 +++++-
 arch/arm/plat-omap/dmtimer.c                       |  719 ++++++++++++--------
 arch/arm/plat-omap/include/plat/dmtimer.h          |  137 +++-
 14 files changed, 1120 insertions(+), 341 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap
  Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma, Thara Gopinath

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.

Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com
Signed-off-by: Thara Gopinath <thara@ti.com>
Acked-by: Cousson, Benoit <b-cousson@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(-)

diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index debc040..14a6277 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -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),
 };
 
 /*
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index 96a942e..ea6717c 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -1998,6 +1998,54 @@ static struct omap_clk omap2430_clks[] = {
 	CLK(NULL,	"mdm_intc_ick",	&mdm_intc_ick,	CK_243X),
 	CLK("omap_hsmmc.0", "mmchsdb_fck",	&mmchsdb1_fck,	CK_243X),
 	CLK("omap_hsmmc.1", "mmchsdb_fck",	&mmchsdb2_fck,	CK_243X),
+	CLK("omap_timer.1",     "fck",  &gpt1_fck,      CK_243X),
+	CLK("omap_timer.2",     "fck",  &gpt2_fck,      CK_243X),
+	CLK("omap_timer.3",     "fck",  &gpt3_fck,      CK_243X),
+	CLK("omap_timer.4",     "fck",  &gpt4_fck,      CK_243X),
+	CLK("omap_timer.5",     "fck",  &gpt5_fck,      CK_243X),
+	CLK("omap_timer.6",     "fck",  &gpt6_fck,      CK_243X),
+	CLK("omap_timer.7",     "fck",  &gpt7_fck,      CK_243X),
+	CLK("omap_timer.8",     "fck",  &gpt8_fck,      CK_243X),
+	CLK("omap_timer.9",     "fck",  &gpt9_fck,      CK_243X),
+	CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_243X),
+	CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_243X),
+	CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_243X),
+	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),
 };
 
 /*
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index dadb8c6..65dd363 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3464,6 +3464,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),
 };
 
 
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index c0b6fbd..946bf04 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -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)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti at ti.com
Signed-off-by: Thara Gopinath <thara@ti.com>
Acked-by: Cousson, Benoit <b-cousson@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(-)

diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index debc040..14a6277 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -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),
 };
 
 /*
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index 96a942e..ea6717c 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -1998,6 +1998,54 @@ static struct omap_clk omap2430_clks[] = {
 	CLK(NULL,	"mdm_intc_ick",	&mdm_intc_ick,	CK_243X),
 	CLK("omap_hsmmc.0", "mmchsdb_fck",	&mmchsdb1_fck,	CK_243X),
 	CLK("omap_hsmmc.1", "mmchsdb_fck",	&mmchsdb2_fck,	CK_243X),
+	CLK("omap_timer.1",     "fck",  &gpt1_fck,      CK_243X),
+	CLK("omap_timer.2",     "fck",  &gpt2_fck,      CK_243X),
+	CLK("omap_timer.3",     "fck",  &gpt3_fck,      CK_243X),
+	CLK("omap_timer.4",     "fck",  &gpt4_fck,      CK_243X),
+	CLK("omap_timer.5",     "fck",  &gpt5_fck,      CK_243X),
+	CLK("omap_timer.6",     "fck",  &gpt6_fck,      CK_243X),
+	CLK("omap_timer.7",     "fck",  &gpt7_fck,      CK_243X),
+	CLK("omap_timer.8",     "fck",  &gpt8_fck,      CK_243X),
+	CLK("omap_timer.9",     "fck",  &gpt9_fck,      CK_243X),
+	CLK("omap_timer.10",    "fck",  &gpt10_fck,     CK_243X),
+	CLK("omap_timer.11",    "fck",  &gpt11_fck,     CK_243X),
+	CLK("omap_timer.12",    "fck",  &gpt12_fck,     CK_243X),
+	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),
 };
 
 /*
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index dadb8c6..65dd363 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3464,6 +3464,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),
 };
 
 
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index c0b6fbd..946bf04 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 02/12] OMAP1: dmtimer: conversion to platform devices
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap
  Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma, Thara Gopinath

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

Signed-off-by: Thara Gopinath <thara@ti.com>
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/mach-omap1/Makefile              |    2 +-
 arch/arm/mach-omap1/timer.c               |  173 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/dmtimer.c              |   56 ++--------
 arch/arm/plat-omap/include/plat/dmtimer.h |    8 ++
 4 files changed, 194 insertions(+), 45 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c

diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 5b114d1..11c85cd 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -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
 
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
new file mode 100644
index 0000000..6e90665
--- /dev/null
+++ b/arch/arm/mach-omap1/timer.c
@@ -0,0 +1,173 @@
+/**
+ * OMAP1 Dual-Mode Timers - platform device registration
+ *
+ * Contains first level initialization routines which internally
+ * generates timer device information and registers with linux
+ * device model. It also has low level function to chnage the timer
+ * input clock source.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+
+#include <plat/dmtimer.h>
+
+#define OMAP1610_GPTIMER1_BASE		0xfffb1400
+#define OMAP1610_GPTIMER2_BASE		0xfffb1c00
+#define OMAP1610_GPTIMER3_BASE		0xfffb2400
+#define OMAP1610_GPTIMER4_BASE		0xfffb2c00
+#define OMAP1610_GPTIMER5_BASE		0xfffb3400
+#define OMAP1610_GPTIMER6_BASE		0xfffb3c00
+#define OMAP1610_GPTIMER7_BASE		0xfffb7400
+#define OMAP1610_GPTIMER8_BASE		0xfffbd400
+
+#define OMAP1_DM_TIMER_COUNT		8
+
+static int omap1_dm_timer_set_src(struct platform_device *pdev,
+				int source)
+{
+	int n = (pdev->id - 1) << 1;
+	u32 l;
+
+	l = __raw_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+	l |= source << n;
+	__raw_writel(l, MOD_CONF_CTRL_1);
+
+	return 0;
+}
+
+
+int __init omap1_dm_timer_init(void)
+{
+	int i;
+	int ret;
+	struct dmtimer_platform_data *pdata;
+	struct platform_device *pdev;
+
+	if (!cpu_is_omap16xx())
+		return 0;
+
+	for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
+		struct resource res[2];
+		u32 base, irq;
+
+		switch (i) {
+		case 1:
+			base = OMAP1610_GPTIMER1_BASE;
+			irq = INT_1610_GPTIMER1;
+			break;
+		case 2:
+			base = OMAP1610_GPTIMER2_BASE;
+			irq = INT_1610_GPTIMER2;
+			break;
+		case 3:
+			base = OMAP1610_GPTIMER3_BASE;
+			irq = INT_1610_GPTIMER3;
+			break;
+		case 4:
+			base = OMAP1610_GPTIMER4_BASE;
+			irq = INT_1610_GPTIMER4;
+			break;
+		case 5:
+			base = OMAP1610_GPTIMER5_BASE;
+			irq = INT_1610_GPTIMER5;
+			break;
+		case 6:
+			base = OMAP1610_GPTIMER6_BASE;
+			irq = INT_1610_GPTIMER6;
+			break;
+		case 7:
+			base = OMAP1610_GPTIMER7_BASE;
+			irq = INT_1610_GPTIMER7;
+			break;
+		case 8:
+			base = OMAP1610_GPTIMER8_BASE;
+			irq = INT_1610_GPTIMER8;
+			break;
+		default:
+			/*
+			 * not supposed to reach here.
+			 * this is to remove warning.
+			 */
+			return -EINVAL;
+		}
+
+		pdev = platform_device_alloc("omap_timer", i);
+		if (!pdev) {
+			pr_err("%s: Failed to device alloc for dmtimer%d\n",
+				__func__, i);
+			return -ENOMEM;
+		}
+
+		memset(res, 0, 2 * sizeof(struct resource));
+		res[0].start = base;
+		res[0].end = base + 0x46;
+		res[0].flags = IORESOURCE_MEM;
+		res[1].start = irq;
+		res[1].end = irq;
+		res[1].flags = IORESOURCE_IRQ;
+		ret = platform_device_add_resources(pdev, res,
+				ARRAY_SIZE(res));
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add resources.\n",
+				__func__);
+			goto err_free_pdev;
+		}
+
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&pdev->dev, "%s: Failed to allocate pdata.\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err_free_pdata;
+		}
+
+		pdata->set_timer_src = omap1_dm_timer_set_src;
+		pdata->needs_manual_reset = 1;
+
+		ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
+				__func__);
+			goto err_free_pdata;
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
+				__func__);
+			goto err_free_pdata;
+		}
+
+		dev_dbg(&pdev->dev, " Registered.\n");
+	}
+
+	return 0;
+
+err_free_pdata:
+	kfree(pdata);
+
+err_free_pdev:
+	platform_device_unregister(pdev);
+
+	return ret;
+}
+arch_initcall(omap1_dm_timer_init);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index e23b7cf..571c14b 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -3,6 +3,12 @@
  *
  * OMAP Dual-Mode Timers
  *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * dmtimer adaptation to platform_driver.
+ *
  * Copyright (C) 2005 Nokia Corporation
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
@@ -43,25 +49,6 @@
 
 static int dm_timer_count;
 
-#ifdef CONFIG_ARCH_OMAP1
-static struct omap_dm_timer omap1_dm_timers[] = {
-	{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
-	{ .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
-	{ .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
-	{ .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
-	{ .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
-	{ .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
-	{ .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
-	{ .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
-};
-
-static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
-
-#else
-#define omap1_dm_timers			NULL
-#define omap1_dm_timer_count		0
-#endif	/* CONFIG_ARCH_OMAP1 */
-
 #ifdef CONFIG_ARCH_OMAP2
 static struct omap_dm_timer omap2_dm_timers[] = {
 	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
@@ -410,35 +397,20 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
-#ifdef CONFIG_ARCH_OMAP1
-
-int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
-{
-	int n = (timer - dm_timers) << 1;
-	u32 l;
-
-	l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
-	l |= source << n;
-	omap_writel(l, MOD_CONF_CTRL_1);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
-
-#else
-
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
+#ifdef CONFIG_ARCH_OMAP2PLUS
 	return __omap_dm_timer_set_source(timer->fclk,
 						dm_source_clocks[source]);
+#else
+	return 0;
+#endif
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
-#endif
-
 void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int load)
 {
@@ -582,16 +554,12 @@ static int __init omap_dm_timer_init(void)
 	struct omap_dm_timer *timer;
 	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
 
-	if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
+	if (!cpu_class_is_omap2())
 		return -ENODEV;
 
 	spin_lock_init(&dm_timer_lock);
 
-	if (cpu_class_is_omap1()) {
-		dm_timers = omap1_dm_timers;
-		dm_timer_count = omap1_dm_timer_count;
-		map_size = SZ_2K;
-	} else if (cpu_is_omap24xx()) {
+	if (cpu_is_omap24xx()) {
 		dm_timers = omap2_dm_timers;
 		dm_timer_count = omap2_dm_timer_count;
 		dm_source_names = omap2_dm_source_names;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index a11d0c0..30381b5 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -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
@@ -62,6 +63,12 @@
 struct omap_dm_timer;
 struct clk;
 
+struct dmtimer_platform_data {
+	int (*set_timer_src)(struct platform_device *pdev, int source);
+	int timer_ip_version;
+	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);
@@ -228,6 +235,7 @@ struct omap_dm_timer {
 	unsigned reserved:1;
 	unsigned enabled:1;
 	unsigned posted:1;
+	struct platform_device *pdev;
 };
 
 extern u32 sys_timer_reserved;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 02/12] OMAP1: dmtimer: conversion to platform devices
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Thara Gopinath <thara@ti.com>
Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/mach-omap1/Makefile              |    2 +-
 arch/arm/mach-omap1/timer.c               |  173 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/dmtimer.c              |   56 ++--------
 arch/arm/plat-omap/include/plat/dmtimer.h |    8 ++
 4 files changed, 194 insertions(+), 45 deletions(-)
 create mode 100644 arch/arm/mach-omap1/timer.c

diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 5b114d1..11c85cd 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -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
 
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
new file mode 100644
index 0000000..6e90665
--- /dev/null
+++ b/arch/arm/mach-omap1/timer.c
@@ -0,0 +1,173 @@
+/**
+ * OMAP1 Dual-Mode Timers - platform device registration
+ *
+ * Contains first level initialization routines which internally
+ * generates timer device information and registers with linux
+ * device model. It also has low level function to chnage the timer
+ * input clock source.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+
+#include <plat/dmtimer.h>
+
+#define OMAP1610_GPTIMER1_BASE		0xfffb1400
+#define OMAP1610_GPTIMER2_BASE		0xfffb1c00
+#define OMAP1610_GPTIMER3_BASE		0xfffb2400
+#define OMAP1610_GPTIMER4_BASE		0xfffb2c00
+#define OMAP1610_GPTIMER5_BASE		0xfffb3400
+#define OMAP1610_GPTIMER6_BASE		0xfffb3c00
+#define OMAP1610_GPTIMER7_BASE		0xfffb7400
+#define OMAP1610_GPTIMER8_BASE		0xfffbd400
+
+#define OMAP1_DM_TIMER_COUNT		8
+
+static int omap1_dm_timer_set_src(struct platform_device *pdev,
+				int source)
+{
+	int n = (pdev->id - 1) << 1;
+	u32 l;
+
+	l = __raw_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+	l |= source << n;
+	__raw_writel(l, MOD_CONF_CTRL_1);
+
+	return 0;
+}
+
+
+int __init omap1_dm_timer_init(void)
+{
+	int i;
+	int ret;
+	struct dmtimer_platform_data *pdata;
+	struct platform_device *pdev;
+
+	if (!cpu_is_omap16xx())
+		return 0;
+
+	for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
+		struct resource res[2];
+		u32 base, irq;
+
+		switch (i) {
+		case 1:
+			base = OMAP1610_GPTIMER1_BASE;
+			irq = INT_1610_GPTIMER1;
+			break;
+		case 2:
+			base = OMAP1610_GPTIMER2_BASE;
+			irq = INT_1610_GPTIMER2;
+			break;
+		case 3:
+			base = OMAP1610_GPTIMER3_BASE;
+			irq = INT_1610_GPTIMER3;
+			break;
+		case 4:
+			base = OMAP1610_GPTIMER4_BASE;
+			irq = INT_1610_GPTIMER4;
+			break;
+		case 5:
+			base = OMAP1610_GPTIMER5_BASE;
+			irq = INT_1610_GPTIMER5;
+			break;
+		case 6:
+			base = OMAP1610_GPTIMER6_BASE;
+			irq = INT_1610_GPTIMER6;
+			break;
+		case 7:
+			base = OMAP1610_GPTIMER7_BASE;
+			irq = INT_1610_GPTIMER7;
+			break;
+		case 8:
+			base = OMAP1610_GPTIMER8_BASE;
+			irq = INT_1610_GPTIMER8;
+			break;
+		default:
+			/*
+			 * not supposed to reach here.
+			 * this is to remove warning.
+			 */
+			return -EINVAL;
+		}
+
+		pdev = platform_device_alloc("omap_timer", i);
+		if (!pdev) {
+			pr_err("%s: Failed to device alloc for dmtimer%d\n",
+				__func__, i);
+			return -ENOMEM;
+		}
+
+		memset(res, 0, 2 * sizeof(struct resource));
+		res[0].start = base;
+		res[0].end = base + 0x46;
+		res[0].flags = IORESOURCE_MEM;
+		res[1].start = irq;
+		res[1].end = irq;
+		res[1].flags = IORESOURCE_IRQ;
+		ret = platform_device_add_resources(pdev, res,
+				ARRAY_SIZE(res));
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add resources.\n",
+				__func__);
+			goto err_free_pdev;
+		}
+
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&pdev->dev, "%s: Failed to allocate pdata.\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err_free_pdata;
+		}
+
+		pdata->set_timer_src = omap1_dm_timer_set_src;
+		pdata->needs_manual_reset = 1;
+
+		ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
+				__func__);
+			goto err_free_pdata;
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
+				__func__);
+			goto err_free_pdata;
+		}
+
+		dev_dbg(&pdev->dev, " Registered.\n");
+	}
+
+	return 0;
+
+err_free_pdata:
+	kfree(pdata);
+
+err_free_pdev:
+	platform_device_unregister(pdev);
+
+	return ret;
+}
+arch_initcall(omap1_dm_timer_init);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index e23b7cf..571c14b 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -3,6 +3,12 @@
  *
  * OMAP Dual-Mode Timers
  *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * dmtimer adaptation to platform_driver.
+ *
  * Copyright (C) 2005 Nokia Corporation
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
@@ -43,25 +49,6 @@
 
 static int dm_timer_count;
 
-#ifdef CONFIG_ARCH_OMAP1
-static struct omap_dm_timer omap1_dm_timers[] = {
-	{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
-	{ .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
-	{ .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
-	{ .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
-	{ .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
-	{ .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
-	{ .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
-	{ .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
-};
-
-static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
-
-#else
-#define omap1_dm_timers			NULL
-#define omap1_dm_timer_count		0
-#endif	/* CONFIG_ARCH_OMAP1 */
-
 #ifdef CONFIG_ARCH_OMAP2
 static struct omap_dm_timer omap2_dm_timers[] = {
 	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
@@ -410,35 +397,20 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
-#ifdef CONFIG_ARCH_OMAP1
-
-int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
-{
-	int n = (timer - dm_timers) << 1;
-	u32 l;
-
-	l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
-	l |= source << n;
-	omap_writel(l, MOD_CONF_CTRL_1);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
-
-#else
-
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
+#ifdef CONFIG_ARCH_OMAP2PLUS
 	return __omap_dm_timer_set_source(timer->fclk,
 						dm_source_clocks[source]);
+#else
+	return 0;
+#endif
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
-#endif
-
 void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int load)
 {
@@ -582,16 +554,12 @@ static int __init omap_dm_timer_init(void)
 	struct omap_dm_timer *timer;
 	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
 
-	if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
+	if (!cpu_class_is_omap2())
 		return -ENODEV;
 
 	spin_lock_init(&dm_timer_lock);
 
-	if (cpu_class_is_omap1()) {
-		dm_timers = omap1_dm_timers;
-		dm_timer_count = omap1_dm_timer_count;
-		map_size = SZ_2K;
-	} else if (cpu_is_omap24xx()) {
+	if (cpu_is_omap24xx()) {
 		dm_timers = omap2_dm_timers;
 		dm_timer_count = omap2_dm_timer_count;
 		dm_source_names = omap2_dm_source_names;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index a11d0c0..30381b5 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -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
@@ -62,6 +63,12 @@
 struct omap_dm_timer;
 struct clk;
 
+struct dmtimer_platform_data {
+	int (*set_timer_src)(struct platform_device *pdev, int source);
+	int timer_ip_version;
+	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);
@@ -228,6 +235,7 @@ struct omap_dm_timer {
 	unsigned reserved:1;
 	unsigned enabled:1;
 	unsigned posted:1;
+	struct platform_device *pdev;
 };
 
 extern u32 sys_timer_reserved;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 03/12] OMAP2+: dmtimer: convert to platform devices
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap
  Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma, Thara Gopinath

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 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 |   22 +++++
 arch/arm/mach-omap2/timer.c                |  136 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/dmtimer.h  |   12 +++-
 6 files changed, 240 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index b6ea69a..6d72062 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -269,6 +269,16 @@ static struct omap_hwmod omap2420_iva_hwmod = {
 	.masters_cnt	= ARRAY_SIZE(omap2420_iva_masters),
 };
 
+/* 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;
 
@@ -309,6 +319,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,
@@ -345,6 +356,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,
@@ -381,6 +393,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,
@@ -417,6 +430,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,
@@ -453,6 +467,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,
@@ -490,6 +505,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,
@@ -526,6 +542,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,
@@ -562,6 +579,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,
@@ -598,6 +616,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,
@@ -634,6 +653,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,
@@ -670,6 +690,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,
@@ -706,6 +727,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 56de8d6..a2580d0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -343,6 +343,16 @@ static struct omap_hwmod omap2430_iva_hwmod = {
 	.masters_cnt	= ARRAY_SIZE(omap2430_iva_masters),
 };
 
+/* 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;
 
@@ -383,6 +393,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,
@@ -419,6 +430,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,
@@ -455,6 +467,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,
@@ -491,6 +504,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,
@@ -527,6 +541,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,
@@ -563,6 +578,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,
@@ -599,6 +615,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,
@@ -635,6 +652,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,
@@ -671,6 +689,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,
@@ -707,6 +726,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,
@@ -743,6 +763,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,
@@ -779,6 +800,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ab35acb..2e4852d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -564,6 +564,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;
 
@@ -604,6 +619,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,
@@ -649,6 +665,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,
@@ -694,6 +711,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,
@@ -739,6 +757,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,
@@ -784,6 +803,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,
@@ -829,6 +849,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,
@@ -874,6 +895,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,
@@ -919,6 +941,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,
@@ -964,6 +987,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,
@@ -1000,6 +1024,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,
@@ -1036,6 +1061,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,
@@ -1085,6 +1111,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index caaf409..393afac 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -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"
 
@@ -4201,6 +4202,16 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
 	.sysc	= &omap44xx_timer_sysc,
 };
 
+/* 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[] = {
@@ -4244,6 +4255,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),
 };
@@ -4291,6 +4303,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),
 };
@@ -4338,6 +4351,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),
 };
@@ -4385,6 +4399,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),
 };
@@ -4451,6 +4466,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),
 };
@@ -4518,6 +4534,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),
 };
@@ -4584,6 +4601,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),
 };
@@ -4650,6 +4668,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),
 };
@@ -4697,6 +4716,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),
 };
@@ -4744,6 +4764,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),
 };
@@ -4791,6 +4812,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),
 };
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 21d34fb..2b6632c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -35,6 +35,7 @@
 #include <linux/irq.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/slab.h>
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
@@ -42,6 +43,7 @@
 #include <asm/sched_clock.h>
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -342,3 +344,137 @@ static void __init omap4_timer_init(void)
 }
 OMAP_SYS_TIMER(4)
 #endif
+
+/**
+ * omap2_dm_timer_set_src - change the timer input clock source
+ * @pdev:	timer platform device pointer
+ * @source:	array index of parent clock source
+ */
+static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
+{
+	int ret;
+	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+	struct clk *fclk, *parent;
+	char *parent_name = NULL;
+
+	fclk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR_OR_NULL(fclk)) {
+		dev_err(&pdev->dev, "%s: %d: clk_get() FAILED\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case OMAP_TIMER_SRC_SYS_CLK:
+		parent_name = "sys_ck";
+		break;
+
+	case OMAP_TIMER_SRC_32_KHZ:
+		parent_name = "32k_ck";
+		break;
+
+	case OMAP_TIMER_SRC_EXT_CLK:
+		if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+			parent_name = "alt_ck";
+			break;
+		}
+		dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
+			__func__, __LINE__);
+		clk_put(fclk);
+		return -EINVAL;
+	}
+
+	parent = clk_get(&pdev->dev, parent_name);
+	if (IS_ERR_OR_NULL(parent)) {
+		dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED\n",
+			__func__, __LINE__, parent_name);
+		clk_put(fclk);
+		return -EINVAL;
+	}
+
+	ret = clk_set_parent(fclk, parent);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED\n",
+			__func__, parent_name);
+		ret = -EINVAL;
+	}
+
+	clk_put(parent);
+	clk_put(fclk);
+
+	return ret;
+}
+
+struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+	{
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func   = omap_device_enable_hwmods,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+/**
+ * omap_timer_init - build and register timer device with an
+ * associated timer hwmod
+ * @oh:	timer hwmod pointer to be used to build timer device
+ * @user:	parameter that can be passed from calling hwmod API
+ *
+ * Called by omap_hwmod_for_each_by_class to register each of the timer
+ * devices present in the system. The number of timer devices is known
+ * by parsing through the hwmod database for a given class name. At the
+ * end of function call memory is allocated for timer device and it is
+ * registered to the framework ready to be proved by the driver.
+ */
+static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
+{
+	int id;
+	int ret = 0;
+	char *name = "omap_timer";
+	struct dmtimer_platform_data *pdata;
+	struct omap_device *od;
+	struct omap_timer_capability_dev_attr *timer_dev_attr;
+
+	pr_debug("%s: %s\n", __func__, oh->name);
+
+	/* on secure device, do not register secure timer */
+	timer_dev_attr = oh->dev_attr;
+	if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
+		if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
+			return ret;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("%s: No memory for [%s]\n", __func__, oh->name);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Extract the IDs from name field in hwmod database
+	 * and use the same for constructing ids' for the
+	 * timer devices. In a way, we are avoiding usage of
+	 * static variable witin the function to do the same.
+	 * CAUTION: We have to be careful and make sure the
+	 * name in hwmod database does not change in which case
+	 * we might either make corresponding change here or
+	 * switch back static variable mechanism.
+	 */
+	sscanf(oh->name, "timer%2d", &id);
+
+	pdata->set_timer_src = omap2_dm_timer_set_src;
+	pdata->timer_ip_version = oh->class->rev;
+
+	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
+			omap2_dmtimer_latency,
+			ARRAY_SIZE(omap2_dmtimer_latency),
+			0);
+
+	if (IS_ERR(od)) {
+		pr_err("%s: Can't build omap_device for %s: %s.\n",
+			__func__, name, oh->name);
+		ret = -EINVAL;
+	}
+
+	kfree(pdata);
+
+	return ret;
+}
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 30381b5..514d4a2 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/dmtimer.h
+ * arch/arm/plat-omap/include/plat/dmtimer.h
  *
  * OMAP Dual-Mode Timers
  *
@@ -60,6 +60,16 @@
  * in OMAP4 can be distinguished.
  */
 #define OMAP_TIMER_IP_VERSION_1                        0x1
+
+/* 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;
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 03/12] OMAP2+: dmtimer: convert to platform devices
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 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 |   22 +++++
 arch/arm/mach-omap2/timer.c                |  136 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/dmtimer.h  |   12 +++-
 6 files changed, 240 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index b6ea69a..6d72062 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -269,6 +269,16 @@ static struct omap_hwmod omap2420_iva_hwmod = {
 	.masters_cnt	= ARRAY_SIZE(omap2420_iva_masters),
 };
 
+/* 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;
 
@@ -309,6 +319,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,
@@ -345,6 +356,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,
@@ -381,6 +393,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,
@@ -417,6 +430,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,
@@ -453,6 +467,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,
@@ -490,6 +505,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,
@@ -526,6 +542,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,
@@ -562,6 +579,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,
@@ -598,6 +616,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,
@@ -634,6 +653,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,
@@ -670,6 +690,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,
@@ -706,6 +727,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 56de8d6..a2580d0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -343,6 +343,16 @@ static struct omap_hwmod omap2430_iva_hwmod = {
 	.masters_cnt	= ARRAY_SIZE(omap2430_iva_masters),
 };
 
+/* 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;
 
@@ -383,6 +393,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,
@@ -419,6 +430,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,
@@ -455,6 +467,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,
@@ -491,6 +504,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,
@@ -527,6 +541,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,
@@ -563,6 +578,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,
@@ -599,6 +615,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,
@@ -635,6 +652,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,
@@ -671,6 +689,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,
@@ -707,6 +726,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,
@@ -743,6 +763,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,
@@ -779,6 +800,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ab35acb..2e4852d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -564,6 +564,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;
 
@@ -604,6 +619,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,
@@ -649,6 +665,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,
@@ -694,6 +711,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,
@@ -739,6 +757,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,
@@ -784,6 +803,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,
@@ -829,6 +849,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,
@@ -874,6 +895,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,
@@ -919,6 +941,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,
@@ -964,6 +987,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,
@@ -1000,6 +1024,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,
@@ -1036,6 +1061,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,
@@ -1085,6 +1111,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,
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index caaf409..393afac 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -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"
 
@@ -4201,6 +4202,16 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
 	.sysc	= &omap44xx_timer_sysc,
 };
 
+/* 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[] = {
@@ -4244,6 +4255,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),
 };
@@ -4291,6 +4303,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),
 };
@@ -4338,6 +4351,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),
 };
@@ -4385,6 +4399,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),
 };
@@ -4451,6 +4466,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),
 };
@@ -4518,6 +4534,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),
 };
@@ -4584,6 +4601,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),
 };
@@ -4650,6 +4668,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),
 };
@@ -4697,6 +4716,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),
 };
@@ -4744,6 +4764,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),
 };
@@ -4791,6 +4812,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),
 };
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 21d34fb..2b6632c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -35,6 +35,7 @@
 #include <linux/irq.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/slab.h>
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
@@ -42,6 +43,7 @@
 #include <asm/sched_clock.h>
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -342,3 +344,137 @@ static void __init omap4_timer_init(void)
 }
 OMAP_SYS_TIMER(4)
 #endif
+
+/**
+ * omap2_dm_timer_set_src - change the timer input clock source
+ * @pdev:	timer platform device pointer
+ * @source:	array index of parent clock source
+ */
+static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
+{
+	int ret;
+	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+	struct clk *fclk, *parent;
+	char *parent_name = NULL;
+
+	fclk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR_OR_NULL(fclk)) {
+		dev_err(&pdev->dev, "%s: %d: clk_get() FAILED\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case OMAP_TIMER_SRC_SYS_CLK:
+		parent_name = "sys_ck";
+		break;
+
+	case OMAP_TIMER_SRC_32_KHZ:
+		parent_name = "32k_ck";
+		break;
+
+	case OMAP_TIMER_SRC_EXT_CLK:
+		if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+			parent_name = "alt_ck";
+			break;
+		}
+		dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
+			__func__, __LINE__);
+		clk_put(fclk);
+		return -EINVAL;
+	}
+
+	parent = clk_get(&pdev->dev, parent_name);
+	if (IS_ERR_OR_NULL(parent)) {
+		dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED\n",
+			__func__, __LINE__, parent_name);
+		clk_put(fclk);
+		return -EINVAL;
+	}
+
+	ret = clk_set_parent(fclk, parent);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED\n",
+			__func__, parent_name);
+		ret = -EINVAL;
+	}
+
+	clk_put(parent);
+	clk_put(fclk);
+
+	return ret;
+}
+
+struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+	{
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func   = omap_device_enable_hwmods,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+/**
+ * omap_timer_init - build and register timer device with an
+ * associated timer hwmod
+ * @oh:	timer hwmod pointer to be used to build timer device
+ * @user:	parameter that can be passed from calling hwmod API
+ *
+ * Called by omap_hwmod_for_each_by_class to register each of the timer
+ * devices present in the system. The number of timer devices is known
+ * by parsing through the hwmod database for a given class name. At the
+ * end of function call memory is allocated for timer device and it is
+ * registered to the framework ready to be proved by the driver.
+ */
+static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
+{
+	int id;
+	int ret = 0;
+	char *name = "omap_timer";
+	struct dmtimer_platform_data *pdata;
+	struct omap_device *od;
+	struct omap_timer_capability_dev_attr *timer_dev_attr;
+
+	pr_debug("%s: %s\n", __func__, oh->name);
+
+	/* on secure device, do not register secure timer */
+	timer_dev_attr = oh->dev_attr;
+	if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
+		if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
+			return ret;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("%s: No memory for [%s]\n", __func__, oh->name);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Extract the IDs from name field in hwmod database
+	 * and use the same for constructing ids' for the
+	 * timer devices. In a way, we are avoiding usage of
+	 * static variable witin the function to do the same.
+	 * CAUTION: We have to be careful and make sure the
+	 * name in hwmod database does not change in which case
+	 * we might either make corresponding change here or
+	 * switch back static variable mechanism.
+	 */
+	sscanf(oh->name, "timer%2d", &id);
+
+	pdata->set_timer_src = omap2_dm_timer_set_src;
+	pdata->timer_ip_version = oh->class->rev;
+
+	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
+			omap2_dmtimer_latency,
+			ARRAY_SIZE(omap2_dmtimer_latency),
+			0);
+
+	if (IS_ERR(od)) {
+		pr_err("%s: Can't build omap_device for %s: %s.\n",
+			__func__, name, oh->name);
+		ret = -EINVAL;
+	}
+
+	kfree(pdata);
+
+	return ret;
+}
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 30381b5..514d4a2 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/dmtimer.h
+ * arch/arm/plat-omap/include/plat/dmtimer.h
  *
  * OMAP Dual-Mode Timers
  *
@@ -60,6 +60,16 @@
  * in OMAP4 can be distinguished.
  */
 #define OMAP_TIMER_IP_VERSION_1                        0x1
+
+/* 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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 04/12] OMAP: dmtimer: platform driver
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap
  Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma, Thara Gopinath

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

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |  139 +++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/dmtimer.h |    2 +
 2 files changed, 135 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 571c14b..92d5aff 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -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
@@ -549,6 +545,137 @@ 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;
+	}
+
+	timer->id = pdev->id;
+	timer->irq = irq->start;
+	timer->pdev = pdev;
+	__omap_dm_timer_init_regs(timer);
+
+	/* 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;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 514d4a2..e8f1c4b 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -229,6 +229,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;
@@ -246,6 +247,7 @@ struct omap_dm_timer {
 	unsigned enabled:1;
 	unsigned posted:1;
 	struct platform_device *pdev;
+	struct list_head node;
 };
 
 extern u32 sys_timer_reserved;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 04/12] OMAP: dmtimer: platform driver
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |  139 +++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/dmtimer.h |    2 +
 2 files changed, 135 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 571c14b..92d5aff 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -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
@@ -549,6 +545,137 @@ 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;
+	}
+
+	timer->id = pdev->id;
+	timer->irq = irq->start;
+	timer->pdev = pdev;
+	__omap_dm_timer_init_regs(timer);
+
+	/* 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;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 514d4a2..e8f1c4b 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -229,6 +229,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;
@@ -246,6 +247,7 @@ struct omap_dm_timer {
 	unsigned enabled:1;
 	unsigned posted:1;
 	struct platform_device *pdev;
+	struct list_head node;
 };
 
 extern u32 sys_timer_reserved;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, 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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/mach-omap2/timer.c               |   22 ++-
 arch/arm/plat-omap/dmtimer.c              |  353 +++++++++--------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |   26 +-
 3 files changed, 140 insertions(+), 261 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 2b6632c..e042b3c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -106,7 +106,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
 	u32 period;
 
-	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate, true);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
@@ -478,3 +478,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);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 92d5aff..b486fd2 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,120 +36,22 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/slab.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
-	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
-	"sys_ck",
-	"func_32k_ck",
-	"alt_ck",
-	NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers			NULL
-#define omap2_dm_timer_count		0
-#define omap2_dm_source_names		NULL
-#define omap2_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
-	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
-	"sys_ck",
-	"omap_32k_fck",
-	NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
-
-#else
-#define omap3_dm_timers			NULL
-#define omap3_dm_timer_count		0
-#define omap3_dm_source_names		NULL
-#define omap3_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
-	{ .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
-	{ .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
-	{ .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
-	{ .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
-	{ .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
-	{ .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
-	{ .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
-	{ .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
-	{ .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
-	{ .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
-	"sys_clkin_ck",
-	"sys_32k_ck",
-	NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+#include <linux/err.h>
 
-#else
-#define omap4_dm_timers			NULL
-#define omap4_dm_timer_count		0
-#define omap4_dm_source_names		NULL
-#define omap4_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
 
-static spinlock_t dm_timer_lock;
 static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
 
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which read operation to perform
+ * @reg:        lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
@@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 	return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which write operation is to perform
+ * @reg:        lowest byte holds the register offset
+ * @value:      data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
  */
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 						u32 value)
@@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-	int autoidle = 0, wakeup = 0;
-
-	if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
-	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
-	/* Enable autoidle on OMAP2+ */
-	if (cpu_class_is_omap2())
-		autoidle = 1;
-
-	/*
-	 * Enable wake-up on OMAP2 CPUs.
-	 */
-	if (cpu_class_is_omap2())
-		wakeup = 1;
 
-	__omap_dm_timer_reset(timer, autoidle, wakeup);
+	__omap_dm_timer_reset(timer, 0, 0);
 	timer->posted = 1;
 }
 
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	int ret;
+
+	timer->fclk = clk_get(&timer->pdev->dev, "fck");
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+		timer->fclk = NULL;
+		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+		return -EINVAL;
+	}
+
 	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
+
+	if (pdata->needs_manual_reset)
+		omap_dm_timer_reset(timer);
+
+	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+	timer->posted = 1;
+	return ret;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
 {
-	struct omap_dm_timer *timer = NULL;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
-	int i;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	for (i = 0; i < dm_timer_count; i++) {
-		if (dm_timers[i].reserved)
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->reserved)
 			continue;
 
-		timer = &dm_timers[i];
+		timer = t;
 		timer->reserved = 1;
 		break;
 	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	if (timer != NULL)
-		omap_dm_timer_prepare(timer);
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
+
+	if (!timer)
+		pr_debug("%s: timer request failed!\n", __func__);
 
 	return timer;
 }
@@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 
 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
-	struct omap_dm_timer *timer;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
-		spin_unlock_irqrestore(&dm_timer_lock, flags);
-		printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
-		       __FILE__, __LINE__, __func__, id);
-		dump_stack();
-		return NULL;
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->pdev->id == id && !t->reserved) {
+			timer = t;
+			timer->reserved = 1;
+			break;
+		}
 	}
-
-	timer = &dm_timers[id-1];
-	timer->reserved = 1;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	omap_dm_timer_prepare(timer);
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
+
+	if (!timer)
+		pr_debug("%s: timer%d request failed!\n", __func__, id);
 
 	return timer;
 }
@@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
 	omap_dm_timer_disable(timer);
+	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
 	timer->reserved = 0;
@@ -278,15 +202,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_enable(timer->fclk);
 		clk_enable(timer->iclk);
 	}
-#endif
 
 	timer->enabled = 1;
 }
@@ -294,15 +218,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_disable(timer->iclk);
 		clk_disable(timer->fclk);
 	}
-#endif
 
 	timer->enabled = 0;
 }
@@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-	int i;
+	int i = 0;
+	struct omap_dm_timer *timer = NULL;
+	unsigned long flags;
 
 	/* If ARMXOR cannot be idled this function call is unnecessary */
 	if (!(inputmask & (1 << 1)))
 		return inputmask;
 
 	/* If any active timer is using ARMXOR return modified mask */
-	for (i = 0; i < dm_timer_count; i++) {
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		u32 l;
 
-		l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 		if (l & OMAP_TIMER_CTRL_ST) {
 			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 				inputmask &= ~(1 << 1);
 			else
 				inputmask &= ~(1 << 2);
 		}
+		i++;
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	return inputmask;
 }
@@ -384,26 +313,31 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	bool is_omap2 = true;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	rate = clk_get_rate(timer->fclk);
-#endif
+	if (pdata->needs_manual_reset)
+		is_omap2 = false;
+	else
+		rate = clk_get_rate(timer->fclk);
 
-	__omap_dm_timer_stop(timer, timer->posted, rate);
+	__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
 }
 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;
+
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	return __omap_dm_timer_set_source(timer->fclk,
-						dm_source_clocks[source]);
-#else
-	return 0;
-#endif
+	omap_dm_timer_disable(timer);
+	ret = pdata->set_timer_src(timer->pdev, source);
+	omap_dm_timer_enable(timer);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
@@ -526,13 +460,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
 int omap_dm_timers_active(void)
 {
-	int i;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		struct omap_dm_timer *timer;
-
-		timer = &dm_timers[i];
+	struct omap_dm_timer *timer;
 
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		if (!timer->enabled)
 			continue;
 
@@ -602,7 +532,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
-	__omap_dm_timer_init_regs(timer);
 
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -675,73 +604,3 @@ 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;
-	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
-
-	if (!cpu_class_is_omap2())
-		return -ENODEV;
-
-	spin_lock_init(&dm_timer_lock);
-
-	if (cpu_is_omap24xx()) {
-		dm_timers = omap2_dm_timers;
-		dm_timer_count = omap2_dm_timer_count;
-		dm_source_names = omap2_dm_source_names;
-		dm_source_clocks = omap2_dm_source_clocks;
-	} else if (cpu_is_omap34xx()) {
-		dm_timers = omap3_dm_timers;
-		dm_timer_count = omap3_dm_timer_count;
-		dm_source_names = omap3_dm_source_names;
-		dm_source_clocks = omap3_dm_source_clocks;
-	} else if (cpu_is_omap44xx()) {
-		dm_timers = omap4_dm_timers;
-		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())
-		for (i = 0; dm_source_names[i] != NULL; i++)
-			dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
-
-	if (cpu_is_omap243x())
-		dm_timers[0].phys_base = 0x49018000;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		timer = &dm_timers[i];
-
-		/* Static mapping, never released */
-		timer->io_base = ioremap(timer->phys_base, map_size);
-		BUG_ON(!timer->io_base);
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-		if (cpu_class_is_omap2()) {
-			char clk_name[16];
-			sprintf(clk_name, "gpt%d_ick", i + 1);
-			timer->iclk = clk_get(NULL, clk_name);
-			sprintf(clk_name, "gpt%d_fck", i + 1);
-			timer->fclk = clk_get(NULL, clk_name);
-		}
-
-		/* One or two timers may be set up early for sys_timer */
-		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_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index e8f1c4b..6cedc73 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -231,9 +231,8 @@ struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
 	int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
 	struct clk *iclk, *fclk;
-#endif
+
 	void __iomem	*io_base;
 	void __iomem	*sys_stat;	/* TISTAT timer status */
 	void __iomem	*irq_stat;	/* TISR/IRQSTATUS interrupt status */
@@ -251,7 +250,7 @@ struct omap_dm_timer {
 };
 
 extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)
@@ -339,7 +338,7 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
 }
 
 static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
-					int posted, unsigned long rate)
+				int posted, unsigned long rate, bool is_omap2)
 {
 	u32 l;
 
@@ -347,15 +346,16 @@ static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
 	if (l & OMAP_TIMER_CTRL_ST) {
 		l &= ~0x1;
 		__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(timer, OMAP_TIMER_CTRL_REG, posted);
-		/*
-		 * Wait for functional clock period x 3.5 to make sure that
-		 * timer is stopped
-		 */
-		udelay(3500000 / rate + 1);
-#endif
+		if (is_omap2) {
+			/* Readback to make sure write has completed */
+			__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
+			 */
+			udelay(3500000 / rate + 1);
+		}
 	}
 
 	/* Ack possibly pending interrupt */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/mach-omap2/timer.c               |   22 ++-
 arch/arm/plat-omap/dmtimer.c              |  353 +++++++++--------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |   26 +-
 3 files changed, 140 insertions(+), 261 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 2b6632c..e042b3c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -106,7 +106,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 {
 	u32 period;
 
-	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate, true);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
@@ -478,3 +478,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);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 92d5aff..b486fd2 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,120 +36,22 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/slab.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
-	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
-	"sys_ck",
-	"func_32k_ck",
-	"alt_ck",
-	NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers			NULL
-#define omap2_dm_timer_count		0
-#define omap2_dm_source_names		NULL
-#define omap2_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
-	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
-	"sys_ck",
-	"omap_32k_fck",
-	NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
-
-#else
-#define omap3_dm_timers			NULL
-#define omap3_dm_timer_count		0
-#define omap3_dm_source_names		NULL
-#define omap3_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
-	{ .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
-	{ .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
-	{ .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
-	{ .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
-	{ .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
-	{ .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
-	{ .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
-	{ .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
-	{ .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
-	{ .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
-	"sys_clkin_ck",
-	"sys_32k_ck",
-	NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+#include <linux/err.h>
 
-#else
-#define omap4_dm_timers			NULL
-#define omap4_dm_timer_count		0
-#define omap4_dm_source_names		NULL
-#define omap4_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
 
-static spinlock_t dm_timer_lock;
 static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
 
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which read operation to perform
+ * @reg:        lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
@@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 	return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which write operation is to perform
+ * @reg:        lowest byte holds the register offset
+ * @value:      data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
  */
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 						u32 value)
@@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-	int autoidle = 0, wakeup = 0;
-
-	if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
-	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
-	/* Enable autoidle on OMAP2+ */
-	if (cpu_class_is_omap2())
-		autoidle = 1;
-
-	/*
-	 * Enable wake-up on OMAP2 CPUs.
-	 */
-	if (cpu_class_is_omap2())
-		wakeup = 1;
 
-	__omap_dm_timer_reset(timer, autoidle, wakeup);
+	__omap_dm_timer_reset(timer, 0, 0);
 	timer->posted = 1;
 }
 
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	int ret;
+
+	timer->fclk = clk_get(&timer->pdev->dev, "fck");
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+		timer->fclk = NULL;
+		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+		return -EINVAL;
+	}
+
 	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
+
+	if (pdata->needs_manual_reset)
+		omap_dm_timer_reset(timer);
+
+	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+	timer->posted = 1;
+	return ret;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
 {
-	struct omap_dm_timer *timer = NULL;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
-	int i;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	for (i = 0; i < dm_timer_count; i++) {
-		if (dm_timers[i].reserved)
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->reserved)
 			continue;
 
-		timer = &dm_timers[i];
+		timer = t;
 		timer->reserved = 1;
 		break;
 	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	if (timer != NULL)
-		omap_dm_timer_prepare(timer);
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
+
+	if (!timer)
+		pr_debug("%s: timer request failed!\n", __func__);
 
 	return timer;
 }
@@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 
 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
-	struct omap_dm_timer *timer;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
-		spin_unlock_irqrestore(&dm_timer_lock, flags);
-		printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
-		       __FILE__, __LINE__, __func__, id);
-		dump_stack();
-		return NULL;
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->pdev->id == id && !t->reserved) {
+			timer = t;
+			timer->reserved = 1;
+			break;
+		}
 	}
-
-	timer = &dm_timers[id-1];
-	timer->reserved = 1;
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	omap_dm_timer_prepare(timer);
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
+
+	if (!timer)
+		pr_debug("%s: timer%d request failed!\n", __func__, id);
 
 	return timer;
 }
@@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
 	omap_dm_timer_disable(timer);
+	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
 	timer->reserved = 0;
@@ -278,15 +202,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_enable(timer->fclk);
 		clk_enable(timer->iclk);
 	}
-#endif
 
 	timer->enabled = 1;
 }
@@ -294,15 +218,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_disable(timer->iclk);
 		clk_disable(timer->fclk);
 	}
-#endif
 
 	timer->enabled = 0;
 }
@@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-	int i;
+	int i = 0;
+	struct omap_dm_timer *timer = NULL;
+	unsigned long flags;
 
 	/* If ARMXOR cannot be idled this function call is unnecessary */
 	if (!(inputmask & (1 << 1)))
 		return inputmask;
 
 	/* If any active timer is using ARMXOR return modified mask */
-	for (i = 0; i < dm_timer_count; i++) {
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		u32 l;
 
-		l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 		if (l & OMAP_TIMER_CTRL_ST) {
 			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 				inputmask &= ~(1 << 1);
 			else
 				inputmask &= ~(1 << 2);
 		}
+		i++;
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	return inputmask;
 }
@@ -384,26 +313,31 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	bool is_omap2 = true;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	rate = clk_get_rate(timer->fclk);
-#endif
+	if (pdata->needs_manual_reset)
+		is_omap2 = false;
+	else
+		rate = clk_get_rate(timer->fclk);
 
-	__omap_dm_timer_stop(timer, timer->posted, rate);
+	__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
 }
 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;
+
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	return __omap_dm_timer_set_source(timer->fclk,
-						dm_source_clocks[source]);
-#else
-	return 0;
-#endif
+	omap_dm_timer_disable(timer);
+	ret = pdata->set_timer_src(timer->pdev, source);
+	omap_dm_timer_enable(timer);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
@@ -526,13 +460,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
 int omap_dm_timers_active(void)
 {
-	int i;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		struct omap_dm_timer *timer;
-
-		timer = &dm_timers[i];
+	struct omap_dm_timer *timer;
 
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		if (!timer->enabled)
 			continue;
 
@@ -602,7 +532,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
-	__omap_dm_timer_init_regs(timer);
 
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -675,73 +604,3 @@ 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;
-	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
-
-	if (!cpu_class_is_omap2())
-		return -ENODEV;
-
-	spin_lock_init(&dm_timer_lock);
-
-	if (cpu_is_omap24xx()) {
-		dm_timers = omap2_dm_timers;
-		dm_timer_count = omap2_dm_timer_count;
-		dm_source_names = omap2_dm_source_names;
-		dm_source_clocks = omap2_dm_source_clocks;
-	} else if (cpu_is_omap34xx()) {
-		dm_timers = omap3_dm_timers;
-		dm_timer_count = omap3_dm_timer_count;
-		dm_source_names = omap3_dm_source_names;
-		dm_source_clocks = omap3_dm_source_clocks;
-	} else if (cpu_is_omap44xx()) {
-		dm_timers = omap4_dm_timers;
-		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())
-		for (i = 0; dm_source_names[i] != NULL; i++)
-			dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
-
-	if (cpu_is_omap243x())
-		dm_timers[0].phys_base = 0x49018000;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		timer = &dm_timers[i];
-
-		/* Static mapping, never released */
-		timer->io_base = ioremap(timer->phys_base, map_size);
-		BUG_ON(!timer->io_base);
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-		if (cpu_class_is_omap2()) {
-			char clk_name[16];
-			sprintf(clk_name, "gpt%d_ick", i + 1);
-			timer->iclk = clk_get(NULL, clk_name);
-			sprintf(clk_name, "gpt%d_fck", i + 1);
-			timer->fclk = clk_get(NULL, clk_name);
-		}
-
-		/* One or two timers may be set up early for sys_timer */
-		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_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index e8f1c4b..6cedc73 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -231,9 +231,8 @@ struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
 	int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
 	struct clk *iclk, *fclk;
-#endif
+
 	void __iomem	*io_base;
 	void __iomem	*sys_stat;	/* TISTAT timer status */
 	void __iomem	*irq_stat;	/* TISR/IRQSTATUS interrupt status */
@@ -251,7 +250,7 @@ struct omap_dm_timer {
 };
 
 extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)
@@ -339,7 +338,7 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
 }
 
 static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
-					int posted, unsigned long rate)
+				int posted, unsigned long rate, bool is_omap2)
 {
 	u32 l;
 
@@ -347,15 +346,16 @@ static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
 	if (l & OMAP_TIMER_CTRL_ST) {
 		l &= ~0x1;
 		__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(timer, OMAP_TIMER_CTRL_REG, posted);
-		/*
-		 * Wait for functional clock period x 3.5 to make sure that
-		 * timer is stopped
-		 */
-		udelay(3500000 / rate + 1);
-#endif
+		if (is_omap2) {
+			/* Readback to make sure write has completed */
+			__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
+			 */
+			udelay(3500000 / rate + 1);
+		}
 	}
 
 	/* Ack possibly pending interrupt */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 06/12] OMAP: dmtimer: pm_runtime support
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap
  Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma, Partha Basak

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Partha Basak <p-basak2@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |   33 ++++++++--------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |    1 -
 2 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index b486fd2..53821a3 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -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>
 
@@ -202,33 +203,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);
 
@@ -463,7 +444,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) &
@@ -533,6 +514,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);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 6cedc73..351b6cd 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -243,7 +243,6 @@ struct omap_dm_timer {
 
 	unsigned long rate;
 	unsigned reserved:1;
-	unsigned enabled:1;
 	unsigned posted:1;
 	struct platform_device *pdev;
 	struct list_head node;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 06/12] OMAP: dmtimer: pm_runtime support
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Signed-off-by: Partha Basak <p-basak2@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |   33 ++++++++--------------------
 arch/arm/plat-omap/include/plat/dmtimer.h |    1 -
 2 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index b486fd2..53821a3 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -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>
 
@@ -202,33 +203,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);
 
@@ -463,7 +444,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) &
@@ -533,6 +514,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);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 6cedc73..351b6cd 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -243,7 +243,6 @@ struct omap_dm_timer {
 
 	unsigned long rate;
 	unsigned reserved:1;
-	unsigned enabled:1;
 	unsigned posted:1;
 	struct platform_device *pdev;
 	struct list_head node;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, 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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Varadarajan, Charulatha <charu@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/include/plat/dmtimer.h |   29 +++++++++++++++++++++++------
 1 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 351b6cd..e29adfa 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -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
 
@@ -227,6 +229,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;
@@ -254,9 +259,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)
 {
-	if (posted)
-		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
+						, MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
+			pr_err("Read timeout!\n");
+	}
 
 	return __raw_readl(timer->func_base + (reg & 0xff));
 }
@@ -264,9 +275,15 @@ static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
 					u32 reg, u32 val, int posted)
 {
-	if (posted)
-		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
+						, MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
+			pr_err("Write timeout!\n");
+	}
 
 	__raw_writel(val, timer->func_base + (reg & 0xff));
 }
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Varadarajan, Charulatha <charu@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
---
 arch/arm/plat-omap/include/plat/dmtimer.h |   29 +++++++++++++++++++++++------
 1 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 351b6cd..e29adfa 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -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
 
@@ -227,6 +229,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;
@@ -254,9 +259,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)
 {
-	if (posted)
-		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
+						, MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
+			pr_err("Read timeout!\n");
+	}
 
 	return __raw_readl(timer->func_base + (reg & 0xff));
 }
@@ -264,9 +275,15 @@ static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
 					u32 reg, u32 val, int posted)
 {
-	if (posted)
-		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
-			cpu_relax();
+	int i = 0;
+
+	if (posted) {
+		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
+						, MAX_WRITE_PEND_WAIT, i);
+
+		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
+			pr_err("Write timeout!\n");
+	}
 
 	__raw_writel(val, timer->func_base + (reg & 0xff));
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma

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 uses them.
Call __omap_dm_timer_init_regs for the remaining timers so that their
base and offsets are configured correctly based upon timer ip version.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |   21 +++++++++++++++++----
 arch/arm/plat-omap/include/plat/dmtimer.h |    1 +
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 53821a3..9c9feb9 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -514,10 +514,23 @@ 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
+
+	if (!timer->reserved) {
+		pm_runtime_get_sync(&pdev->dev);
+		__omap_dm_timer_init_regs(timer);
+		timer->tidr = __raw_readl(timer->io_base);
+		pm_runtime_put(&pdev->dev);
 	}
 
 	/* add the timer element to the list */
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index e29adfa..6413fe2 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -246,6 +246,7 @@ struct omap_dm_timer {
 	void __iomem	*pend;		/* write pending */
 	void __iomem	*func_base;	/* function register base */
 
+	u32 tidr;	/* TIDR register value */
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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 uses them.
Call __omap_dm_timer_init_regs for the remaining timers so that their
base and offsets are configured correctly based upon timer ip version.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |   21 +++++++++++++++++----
 arch/arm/plat-omap/include/plat/dmtimer.h |    1 +
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 53821a3..9c9feb9 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -514,10 +514,23 @@ 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
+
+	if (!timer->reserved) {
+		pm_runtime_get_sync(&pdev->dev);
+		__omap_dm_timer_init_regs(timer);
+		timer->tidr = __raw_readl(timer->io_base);
+		pm_runtime_put(&pdev->dev);
 	}
 
 	/* add the timer element to the list */
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index e29adfa..6413fe2 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -246,6 +246,7 @@ struct omap_dm_timer {
 	void __iomem	*pend;		/* write pending */
 	void __iomem	*func_base;	/* function register base */
 
+	u32 tidr;	/* TIDR register value */
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, 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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/mach-omap2/timer.c               |    9 ++
 arch/arm/plat-omap/dmtimer.c              |  126 +++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/dmtimer.h |   31 +++++++
 3 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index e042b3c..041fed9 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -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 */
 
@@ -433,6 +436,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);
 
@@ -463,6 +467,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_version = 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),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 9c9feb9..f549c63 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 	__omap_dm_timer_write(timer, reg, value, timer->posted);
 }
 
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+				timer->context.tiocp_cfg);
+	if (!(timer->tidr >> 16))
+		__raw_writel(timer->context.tistat, timer->sys_stat);
+
+	__raw_writel(timer->context.tisr, timer->irq_stat);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
+				timer->context.twer);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+				timer->context.tcrr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+				timer->context.tldr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+				timer->context.tmar);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+				timer->context.tsicr);
+	__raw_writel(timer->context.tier, timer->irq_ena);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+				timer->context.tclr);
+}
+
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
 	int c;
@@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer, 0, 0);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return -EINVAL;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
@@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	}
+
+	/* Save the context */
+	timer->context.tclr = l;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
@@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 		rate = clk_get_rate(timer->fclk);
 
 	__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
+
+	if (timer->loses_context) {
+		if (timer->get_context_loss_count)
+			timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+	}
+
+	/*
+	 * Since the register values are computed and written within
+	 * __omap_dm_timer_stop, we need to use read to retrieve the
+	 * context.
+	 */
+	timer->context.tclr =
+			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+	timer->context.tisr = __raw_readl(timer->irq_stat);
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -314,9 +369,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	return ret;
 }
@@ -327,6 +380,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -336,6 +390,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -345,6 +403,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -355,6 +422,11 @@ 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, l, load, timer->posted);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	timer->context.tcrr = load;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -363,6 +435,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -370,6 +443,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tmar = match;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -378,6 +456,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	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));
@@ -387,6 +466,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -394,6 +477,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -401,13 +485,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 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_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
+
+	/* Save the context */
+	timer->context.tier = value;
+	timer->context.twer = value;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -415,6 +509,11 @@ 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);
+		return 0;
+	}
+
 	l = __raw_readl(timer->irq_stat);
 
 	return l;
@@ -424,18 +523,33 @@ 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, value);
+	/* Save the context */
+	timer->context.tisr = value;
 }
 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);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	/* Save the context */
+	timer->context.tcrr = value;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -513,6 +627,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 /*
  * sys_timer_reserved is not defined for OMAP1.
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 6413fe2..577a7a6 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -79,6 +79,9 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	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);
@@ -232,6 +235,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;
@@ -250,8 +276,13 @@ struct omap_dm_timer {
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
+	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;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/mach-omap2/timer.c               |    9 ++
 arch/arm/plat-omap/dmtimer.c              |  126 +++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/dmtimer.h |   31 +++++++
 3 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index e042b3c..041fed9 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -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 */
 
@@ -433,6 +436,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);
 
@@ -463,6 +467,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_version = 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),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 9c9feb9..f549c63 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 	__omap_dm_timer_write(timer, reg, value, timer->posted);
 }
 
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+				timer->context.tiocp_cfg);
+	if (!(timer->tidr >> 16))
+		__raw_writel(timer->context.tistat, timer->sys_stat);
+
+	__raw_writel(timer->context.tisr, timer->irq_stat);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
+				timer->context.twer);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+				timer->context.tcrr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+				timer->context.tldr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+				timer->context.tmar);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+				timer->context.tsicr);
+	__raw_writel(timer->context.tier, timer->irq_ena);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+				timer->context.tclr);
+}
+
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
 	int c;
@@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer, 0, 0);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return -EINVAL;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
@@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	}
+
+	/* Save the context */
+	timer->context.tclr = l;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
@@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 		rate = clk_get_rate(timer->fclk);
 
 	__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
+
+	if (timer->loses_context) {
+		if (timer->get_context_loss_count)
+			timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+	}
+
+	/*
+	 * Since the register values are computed and written within
+	 * __omap_dm_timer_stop, we need to use read to retrieve the
+	 * context.
+	 */
+	timer->context.tclr =
+			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+	timer->context.tisr = __raw_readl(timer->irq_stat);
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -314,9 +369,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	return ret;
 }
@@ -327,6 +380,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -336,6 +390,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -345,6 +403,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -355,6 +422,11 @@ 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, l, load, timer->posted);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	timer->context.tcrr = load;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -363,6 +435,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -370,6 +443,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tmar = match;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -378,6 +456,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	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));
@@ -387,6 +466,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -394,6 +477,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -401,13 +485,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 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_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
+
+	/* Save the context */
+	timer->context.tier = value;
+	timer->context.twer = value;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -415,6 +509,11 @@ 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);
+		return 0;
+	}
+
 	l = __raw_readl(timer->irq_stat);
 
 	return l;
@@ -424,18 +523,33 @@ 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, value);
+	/* Save the context */
+	timer->context.tisr = value;
 }
 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);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	/* Save the context */
+	timer->context.tcrr = value;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -513,6 +627,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 /*
  * sys_timer_reserved is not defined for OMAP1.
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 6413fe2..577a7a6 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -79,6 +79,9 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	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);
@@ -232,6 +235,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;
@@ -250,8 +276,13 @@ struct omap_dm_timer {
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
+	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;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma

The request functions now verify the success of omap_dm_timer_prepare() call
after a timer is acquired. If *_prepare() fails then we have to release the
timer. In order to avoid race condition during this time, include *_prepare()
within lock.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index f549c63..631b6af 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -166,7 +166,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);
@@ -175,6 +174,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__);
@@ -197,7 +197,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);
@@ -206,6 +205,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);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

The request functions now verify the success of omap_dm_timer_prepare() call
after a timer is acquired. If *_prepare() fails then we have to release the
timer. In order to avoid race condition during this time, include *_prepare()
within lock.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index f549c63..631b6af 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -166,7 +166,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);
@@ -175,6 +174,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__);
@@ -197,7 +197,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);
@@ -206,6 +205,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);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 11/12] OMAP: dmtimer: add error handling to export APIs
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma

Add error handling code to export APIs.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |  101 ++++++++++++++++++++++-------
 arch/arm/plat-omap/include/plat/dmtimer.h |   24 ++++----
 2 files changed, 88 insertions(+), 37 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 631b6af..41755ff 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -214,12 +214,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);
 
@@ -237,7 +241,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);
 
@@ -281,7 +287,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);
 
@@ -295,21 +303,25 @@ 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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	if (timer->loses_context) {
@@ -327,15 +339,19 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 
 	/* Save the context */
 	timer->context.tclr = l;
+	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;
 	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 	bool is_omap2 = true;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	if (pdata->needs_manual_reset)
 		is_omap2 = false;
 	else
@@ -358,13 +374,19 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	timer->context.tisr = __raw_readl(timer->irq_stat);
 	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;
@@ -375,11 +397,14 @@ 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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
@@ -394,15 +419,19 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tclr = l;
 	timer->context.tldr = load;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	if (timer->loses_context) {
@@ -427,14 +456,18 @@ 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;
+	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
@@ -448,14 +481,18 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	timer->context.tclr = l;
 	timer->context.tmar = match;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
@@ -470,13 +507,17 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 	/* Save the context */
 	timer->context.tclr = l;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
@@ -489,12 +530,16 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 	/* Save the context */
 	timer->context.tclr = l;
 	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)
 {
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
 
@@ -502,6 +547,7 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 	timer->context.tier = value;
 	timer->context.twer = value;
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -509,8 +555,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;
 	}
 
@@ -520,18 +566,22 @@ 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, value);
 	/* 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;
 	}
 
@@ -539,17 +589,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);
 
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 577a7a6..639957f 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -86,7 +86,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);
 
@@ -95,23 +95,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);
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 11/12] OMAP: dmtimer: add error handling to export APIs
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

Add error handling code to export APIs.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/plat-omap/dmtimer.c              |  101 ++++++++++++++++++++++-------
 arch/arm/plat-omap/include/plat/dmtimer.h |   24 ++++----
 2 files changed, 88 insertions(+), 37 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 631b6af..41755ff 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -214,12 +214,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);
 
@@ -237,7 +241,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);
 
@@ -281,7 +287,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);
 
@@ -295,21 +303,25 @@ 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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	if (timer->loses_context) {
@@ -327,15 +339,19 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 
 	/* Save the context */
 	timer->context.tclr = l;
+	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;
 	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 	bool is_omap2 = true;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	if (pdata->needs_manual_reset)
 		is_omap2 = false;
 	else
@@ -358,13 +374,19 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	timer->context.tisr = __raw_readl(timer->irq_stat);
 	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;
@@ -375,11 +397,14 @@ 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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
@@ -394,15 +419,19 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tclr = l;
 	timer->context.tldr = load;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 
 	if (timer->loses_context) {
@@ -427,14 +456,18 @@ 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;
+	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
@@ -448,14 +481,18 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	timer->context.tclr = l;
 	timer->context.tmar = match;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
@@ -470,13 +507,17 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 	/* Save the context */
 	timer->context.tclr = l;
 	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;
 
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
@@ -489,12 +530,16 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 	/* Save the context */
 	timer->context.tclr = l;
 	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)
 {
+	if (unlikely(!timer))
+		return -EINVAL;
+
 	omap_dm_timer_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
 
@@ -502,6 +547,7 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 	timer->context.tier = value;
 	timer->context.twer = value;
 	omap_dm_timer_disable(timer);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -509,8 +555,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;
 	}
 
@@ -520,18 +566,22 @@ 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, value);
 	/* 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;
 	}
 
@@ -539,17 +589,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);
 
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 577a7a6..639957f 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -86,7 +86,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);
 
@@ -95,23 +95,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);
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  -1 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-omap; +Cc: khilman, tony, linux-arm-kernel, Tarun Kanti DebBarma

We do not need this field in dmtimer_platform_data{} anymore.
Instead, read "tidr" register to identify the ip version now.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |    1 -
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 --
 arch/arm/mach-omap2/timer.c                        |    8 +++++---
 arch/arm/plat-omap/dmtimer.c                       |    2 ++
 arch/arm/plat-omap/include/plat/dmtimer.h          |    7 -------
 5 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 177dee2..dc6ec15 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -43,7 +43,6 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = {
 struct omap_hwmod_class omap2xxx_timer_hwmod_class = {
 	.name	= "timer",
 	.sysc	= &omap2xxx_timer_sysc,
-	.rev	= OMAP_TIMER_IP_VERSION_1,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 2e4852d..463ad78 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -545,7 +545,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
 static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
 	.name = "timer",
 	.sysc = &omap3xxx_timer_1ms_sysc,
-	.rev = OMAP_TIMER_IP_VERSION_1,
 };
 
 static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
@@ -561,7 +560,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
 static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
 	.name = "timer",
 	.sysc = &omap3xxx_timer_sysc,
-	.rev =  OMAP_TIMER_IP_VERSION_1,
 };
 
 /* secure timers dev attribute */
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 041fed9..c784eda 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -356,9 +356,10 @@ OMAP_SYS_TIMER(4)
 static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 {
 	int ret;
-	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+	struct omap_dm_timer *timer = platform_get_drvdata(pdev);
 	struct clk *fclk, *parent;
 	char *parent_name = NULL;
+	u32 tidr;
 
 	fclk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR_OR_NULL(fclk)) {
@@ -377,10 +378,12 @@ static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 		break;
 
 	case OMAP_TIMER_SRC_EXT_CLK:
-		if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+		tidr = __raw_readl(timer->io_base);
+		if (!(tidr >> 16)) {
 			parent_name = "alt_ck";
 			break;
 		}
+
 		dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
 			__func__, __LINE__);
 		clk_put(fclk);
@@ -465,7 +468,6 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	sscanf(oh->name, "timer%2d", &id);
 
 	pdata->set_timer_src = omap2_dm_timer_set_src;
-	pdata->timer_ip_version = oh->class->rev;
 
 	pwrdm = omap_hwmod_get_pwrdm(oh);
 	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 41755ff..b66f93f 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -700,6 +700,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 		pm_runtime_put(&pdev->dev);
 	}
 
+	platform_set_drvdata(pdev, timer);
+
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 639957f..5025c2d 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -57,12 +57,6 @@
 #define OMAP_TIMER_TRIGGER_OVERFLOW		0x01
 #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE	0x02
 
-/*
- * IP revision identifier so that Highlander IP
- * in OMAP4 can be distinguished.
- */
-#define OMAP_TIMER_IP_VERSION_1                        0x1
-
 /* timer capabilities used in hwmod database */
 #define OMAP_TIMER_SECURE				0x80000000
 #define OMAP_TIMER_ALWON				0x40000000
@@ -77,7 +71,6 @@ struct clk;
 
 struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
-	int timer_ip_version;
 	u32 needs_manual_reset:1;
 	bool loses_context;
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field
@ 2011-09-20 11:30   ` Tarun Kanti DebBarma
  0 siblings, 0 replies; 76+ messages in thread
From: Tarun Kanti DebBarma @ 2011-09-20 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

We do not need this field in dmtimer_platform_data{} anymore.
Instead, read "tidr" register to identify the ip version now.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |    1 -
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 --
 arch/arm/mach-omap2/timer.c                        |    8 +++++---
 arch/arm/plat-omap/dmtimer.c                       |    2 ++
 arch/arm/plat-omap/include/plat/dmtimer.h          |    7 -------
 5 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 177dee2..dc6ec15 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -43,7 +43,6 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = {
 struct omap_hwmod_class omap2xxx_timer_hwmod_class = {
 	.name	= "timer",
 	.sysc	= &omap2xxx_timer_sysc,
-	.rev	= OMAP_TIMER_IP_VERSION_1,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 2e4852d..463ad78 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -545,7 +545,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
 static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
 	.name = "timer",
 	.sysc = &omap3xxx_timer_1ms_sysc,
-	.rev = OMAP_TIMER_IP_VERSION_1,
 };
 
 static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
@@ -561,7 +560,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
 static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
 	.name = "timer",
 	.sysc = &omap3xxx_timer_sysc,
-	.rev =  OMAP_TIMER_IP_VERSION_1,
 };
 
 /* secure timers dev attribute */
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 041fed9..c784eda 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -356,9 +356,10 @@ OMAP_SYS_TIMER(4)
 static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 {
 	int ret;
-	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+	struct omap_dm_timer *timer = platform_get_drvdata(pdev);
 	struct clk *fclk, *parent;
 	char *parent_name = NULL;
+	u32 tidr;
 
 	fclk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR_OR_NULL(fclk)) {
@@ -377,10 +378,12 @@ static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 		break;
 
 	case OMAP_TIMER_SRC_EXT_CLK:
-		if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+		tidr = __raw_readl(timer->io_base);
+		if (!(tidr >> 16)) {
 			parent_name = "alt_ck";
 			break;
 		}
+
 		dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
 			__func__, __LINE__);
 		clk_put(fclk);
@@ -465,7 +468,6 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	sscanf(oh->name, "timer%2d", &id);
 
 	pdata->set_timer_src = omap2_dm_timer_set_src;
-	pdata->timer_ip_version = oh->class->rev;
 
 	pwrdm = omap_hwmod_get_pwrdm(oh);
 	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 41755ff..b66f93f 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -700,6 +700,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 		pm_runtime_put(&pdev->dev);
 	}
 
+	platform_set_drvdata(pdev, timer);
+
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 639957f..5025c2d 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -57,12 +57,6 @@
 #define OMAP_TIMER_TRIGGER_OVERFLOW		0x01
 #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE	0x02
 
-/*
- * IP revision identifier so that Highlander IP
- * in OMAP4 can be distinguished.
- */
-#define OMAP_TIMER_IP_VERSION_1                        0x1
-
 /* timer capabilities used in hwmod database */
 #define OMAP_TIMER_SECURE				0x80000000
 #define OMAP_TIMER_ALWON				0x40000000
@@ -77,7 +71,6 @@ struct clk;
 
 struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
-	int timer_ip_version;
 	u32 needs_manual_reset:1;
 	bool loses_context;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  0:42     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  0:42 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> The request functions now verify the success of omap_dm_timer_prepare() call
> after a timer is acquired. If *_prepare() fails then we have to release the
> timer. In order to avoid race condition during this time, include *_prepare()
> within lock.

This I've folded into patch 5.

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
@ 2011-09-22  0:42     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  0:42 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> The request functions now verify the success of omap_dm_timer_prepare() call
> after a timer is acquired. If *_prepare() fails then we have to release the
> timer. In order to avoid race condition during this time, include *_prepare()
> within lock.

This I've folded into patch 5.

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-09-22  0:59   ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  0:59 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

Hi Tarun,

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> Adaptation of dmtimer code to platform driver using omap_device and
> omap_hwmod abstraction. It also include pm-runtime and off-mode support.

I've applied these into dmtimer branch with some changes to simplify
things further. I've also merged it into linux-omap master branch
for further testing.

I'll reply to your patches with the changes I've done. Care give the
dmtimer branch a try and see if I've missed something?

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-22  0:59   ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  0:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tarun,

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> Adaptation of dmtimer code to platform driver using omap_device and
> omap_hwmod abstraction. It also include pm-runtime and off-mode support.

I've applied these into dmtimer branch with some changes to simplify
things further. I've also merged it into linux-omap master branch
for further testing.

I'll reply to your patches with the changes I've done. Care give the
dmtimer branch a try and see if I've missed something?

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -514,10 +514,23 @@ 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
> +
> +	if (!timer->reserved) {
> +		pm_runtime_get_sync(&pdev->dev);
> +		__omap_dm_timer_init_regs(timer);
> +		timer->tidr = __raw_readl(timer->io_base);
> +		pm_runtime_put(&pdev->dev);
>  	}
>  
>  	/* add the timer element to the list */

This all should not be necessary. We can pass the reserved flag
in pdata. Let's replace this one with the patch below.

Regards,

Tony


From: Tony Lindgren <tony@atomide.com>
Date: Wed, 21 Sep 2011 16:38:51 -0700
Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers

Pass the reserved flag in pdata and use it. We can
now make sys_timer_reserved static to mach-omap2/timer.c.

Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 9c2f588..f1e3ec1 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -69,7 +69,7 @@
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID		12
 
-u32 sys_timer_reserved;
+static u32 sys_timer_reserved;
 
 /* Clockevent code */
 
@@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	pdata->set_timer_src = omap2_dm_timer_set_src;
 	pdata->timer_ip_version = oh->class->rev;
 
+	/* Mark clocksource and clockevent timers as reserved */
+	if ((sys_timer_reserved >> (id - 1)) & 0x1)
+		pdata->reserved = 1;
+
 	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
 			omap2_dmtimer_latency,
 			ARRAY_SIZE(omap2_dmtimer_latency),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index ac904c2..c8df3c3 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 
 	timer->id = pdev->id;
 	timer->irq = irq->start;
+	timer->reserved = pdata->reserved;
 	timer->pdev = pdev;
 
 	/* Skip pm_runtime_enable for OMAP1 */
@@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 		pm_runtime_irq_safe(&pdev->dev);
 	}
 
+	if (!timer->reserved) {
+		pm_runtime_get_sync(&pdev->dev);
+		__omap_dm_timer_init_regs(timer);
+		pm_runtime_put(&pdev->dev);
+	}
+
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 4e3a326..29764c3 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -77,6 +77,7 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	u32 needs_manual_reset:1;
+	bool reserved;
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -248,7 +249,6 @@ struct omap_dm_timer {
 	struct list_head node;
 };
 
-extern u32 sys_timer_reserved;
 int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -514,10 +514,23 @@ 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
> +
> +	if (!timer->reserved) {
> +		pm_runtime_get_sync(&pdev->dev);
> +		__omap_dm_timer_init_regs(timer);
> +		timer->tidr = __raw_readl(timer->io_base);
> +		pm_runtime_put(&pdev->dev);
>  	}
>  
>  	/* add the timer element to the list */

This all should not be necessary. We can pass the reserved flag
in pdata. Let's replace this one with the patch below.

Regards,

Tony


From: Tony Lindgren <tony@atomide.com>
Date: Wed, 21 Sep 2011 16:38:51 -0700
Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers

Pass the reserved flag in pdata and use it. We can
now make sys_timer_reserved static to mach-omap2/timer.c.

Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 9c2f588..f1e3ec1 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -69,7 +69,7 @@
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID		12
 
-u32 sys_timer_reserved;
+static u32 sys_timer_reserved;
 
 /* Clockevent code */
 
@@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	pdata->set_timer_src = omap2_dm_timer_set_src;
 	pdata->timer_ip_version = oh->class->rev;
 
+	/* Mark clocksource and clockevent timers as reserved */
+	if ((sys_timer_reserved >> (id - 1)) & 0x1)
+		pdata->reserved = 1;
+
 	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
 			omap2_dmtimer_latency,
 			ARRAY_SIZE(omap2_dmtimer_latency),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index ac904c2..c8df3c3 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 
 	timer->id = pdev->id;
 	timer->irq = irq->start;
+	timer->reserved = pdata->reserved;
 	timer->pdev = pdev;
 
 	/* Skip pm_runtime_enable for OMAP1 */
@@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 		pm_runtime_irq_safe(&pdev->dev);
 	}
 
+	if (!timer->reserved) {
+		pm_runtime_get_sync(&pdev->dev);
+		__omap_dm_timer_init_regs(timer);
+		pm_runtime_put(&pdev->dev);
+	}
+
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_add_tail(&timer->node, &omap_timer_list);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 4e3a326..29764c3 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -77,6 +77,7 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	u32 needs_manual_reset:1;
+	bool reserved;
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -248,7 +249,6 @@ struct omap_dm_timer {
 	struct list_head node;
 };
 
-extern u32 sys_timer_reserved;
 int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> 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.

I've updated this to use revision instead of tidr. Updated patch below.

Regards,

Tony


From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:24 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[tony@atomide.com: updated to use revision instead of tidr]
Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index f1e3ec1..1140e98 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -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 */
 
@@ -433,6 +436,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);
 
@@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	if ((sys_timer_reserved >> (id - 1)) & 0x1)
 		pdata->reserved = 1;
 
+	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),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index c8df3c3..43eb750 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 	__omap_dm_timer_write(timer, reg, value, timer->posted);
 }
 
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+				timer->context.tiocp_cfg);
+	if (timer->revision > 1)
+		__raw_writel(timer->context.tistat, timer->sys_stat);
+
+	__raw_writel(timer->context.tisr, timer->irq_stat);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
+				timer->context.twer);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+				timer->context.tcrr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+				timer->context.tldr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+				timer->context.tmar);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+				timer->context.tsicr);
+	__raw_writel(timer->context.tier, timer->irq_ena);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+				timer->context.tclr);
+}
+
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
 	int c;
@@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer, 0, 0);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return -EINVAL;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
@@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	}
+
+	/* Save the context */
+	timer->context.tclr = l;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
@@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	return ret;
 }
@@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -352,6 +403,11 @@ 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, l, load, timer->posted);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	timer->context.tcrr = load;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tmar = match;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	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));
@@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 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_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
+
+	/* Save the context */
+	timer->context.tier = value;
+	timer->context.twer = value;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -412,6 +490,11 @@ 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);
+		return 0;
+	}
+
 	l = __raw_readl(timer->irq_stat);
 
 	return l;
@@ -421,18 +504,33 @@ 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, value);
+	/* Save the context */
+	timer->context.tisr = value;
 }
 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);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	/* Save the context */
+	timer->context.tcrr = value;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->reserved = pdata->reserved;
 	timer->pdev = pdev;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 	/* Skip pm_runtime_enable for OMAP1 */
 	if (!pdata->needs_manual_reset) {
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 29764c3..9519d87 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
 struct omap_dm_timer;
 struct clk;
 
+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 dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	u32 needs_manual_reset:1;
 	bool reserved;
+
+	bool loses_context;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -245,8 +272,14 @@ struct omap_dm_timer {
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
+	struct timer_regs context;
+	bool loses_context;
+	int ctx_loss_count;
+	int revision;
 	struct platform_device *pdev;
 	struct list_head node;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 int omap_dm_timer_prepare(struct omap_dm_timer *timer);
@@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 	/* Assume v1 ip if bits [31:16] are zero */
 	tidr = __raw_readl(timer->io_base);
 	if (!(tidr >> 16)) {
+		timer->revision = 1;
 		timer->sys_stat = timer->io_base +
 				OMAP_TIMER_V1_SYS_STAT_OFFSET;
 		timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
@@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
 		timer->func_base = timer->io_base;
 	} else {
+		timer->revision = 2;
 		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;

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> 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.

I've updated this to use revision instead of tidr. Updated patch below.

Regards,

Tony


From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:24 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[tony at atomide.com: updated to use revision instead of tidr]
Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index f1e3ec1..1140e98 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -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 */
 
@@ -433,6 +436,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);
 
@@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	if ((sys_timer_reserved >> (id - 1)) & 0x1)
 		pdata->reserved = 1;
 
+	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),
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index c8df3c3..43eb750 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 	__omap_dm_timer_write(timer, reg, value, timer->posted);
 }
 
+static void omap_timer_restore_context(struct omap_dm_timer *timer)
+{
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+				timer->context.tiocp_cfg);
+	if (timer->revision > 1)
+		__raw_writel(timer->context.tistat, timer->sys_stat);
+
+	__raw_writel(timer->context.tisr, timer->irq_stat);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
+				timer->context.twer);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
+				timer->context.tcrr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+				timer->context.tldr);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
+				timer->context.tmar);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
+				timer->context.tsicr);
+	__raw_writel(timer->context.tier, timer->irq_ena);
+	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
+				timer->context.tclr);
+}
+
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
 	int c;
@@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer, 0, 0);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return -EINVAL;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
@@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	}
+
+	/* Save the context */
+	timer->context.tclr = l;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
@@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	return ret;
 }
@@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
+
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (ctx_loss_cnt_after != timer->ctx_loss_count)
+			omap_timer_restore_context(timer);
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -352,6 +403,11 @@ 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, l, load, timer->posted);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tldr = load;
+	timer->context.tcrr = load;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	timer->context.tmar = match;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	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));
@@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+
+	/* Save the context */
+	timer->context.tclr = l;
+	omap_dm_timer_disable(timer);
 }
 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_enable(timer);
 	__omap_dm_timer_int_enable(timer, value);
+
+	/* Save the context */
+	timer->context.tier = value;
+	timer->context.twer = value;
+	omap_dm_timer_disable(timer);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -412,6 +490,11 @@ 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);
+		return 0;
+	}
+
 	l = __raw_readl(timer->irq_stat);
 
 	return l;
@@ -421,18 +504,33 @@ 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, value);
+	/* Save the context */
+	timer->context.tisr = value;
 }
 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);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void 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;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	/* Save the context */
+	timer->context.tcrr = value;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->reserved = pdata->reserved;
 	timer->pdev = pdev;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 	/* Skip pm_runtime_enable for OMAP1 */
 	if (!pdata->needs_manual_reset) {
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 29764c3..9519d87 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
 struct omap_dm_timer;
 struct clk;
 
+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 dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_version;
 	u32 needs_manual_reset:1;
 	bool reserved;
+
+	bool loses_context;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -245,8 +272,14 @@ struct omap_dm_timer {
 	unsigned long rate;
 	unsigned reserved:1;
 	unsigned posted:1;
+	struct timer_regs context;
+	bool loses_context;
+	int ctx_loss_count;
+	int revision;
 	struct platform_device *pdev;
 	struct list_head node;
+
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 int omap_dm_timer_prepare(struct omap_dm_timer *timer);
@@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 	/* Assume v1 ip if bits [31:16] are zero */
 	tidr = __raw_readl(timer->io_base);
 	if (!(tidr >> 16)) {
+		timer->revision = 1;
 		timer->sys_stat = timer->io_base +
 				OMAP_TIMER_V1_SYS_STAT_OFFSET;
 		timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
@@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
 		timer->func_base = timer->io_base;
 	} else {
+		timer->revision = 2;
 		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;

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> We do not need this field in dmtimer_platform_data{} anymore.
> Instead, read "tidr" register to identify the ip version now.

Let's wait a bit on this one as Benoit had some comments regarding
the use of tidr.

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> We do not need this field in dmtimer_platform_data{} anymore.
> Instead, read "tidr" register to identify the ip version now.

Let's wait a bit on this one as Benoit had some comments regarding
the use of tidr.

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma
  Cc: linux-omap, khilman, linux-arm-kernel, Thara Gopinath

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> 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.
> 
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com

I've fixed the missing bracket in the email address     ^^^

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> 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.
> 
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com

I've fixed the missing bracket in the email address     ^^^

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -254,9 +259,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>  static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>  						int posted)
>  {
> -	if (posted)
> -		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> -			cpu_relax();
> +	int i = 0;
> +
> +	if (posted) {
> +		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> +						, MAX_WRITE_PEND_WAIT, i);
> +
> +		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> +			pr_err("Read timeout!\n");
> +	}
>  
>  	return __raw_readl(timer->func_base + (reg & 0xff));
>  }
> @@ -264,9 +275,15 @@ static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>  static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
>  					u32 reg, u32 val, int posted)
>  {
> -	if (posted)
> -		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> -			cpu_relax();
> +	int i = 0;
> +
> +	if (posted) {
> +		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> +						, MAX_WRITE_PEND_WAIT, i);
> +
> +		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> +			pr_err("Write timeout!\n");
> +	}
>  
>  	__raw_writel(val, timer->func_base + (reg & 0xff));
>  }

Let's leave out these changes for now, they make the
omap2_gp_timer_set_next_event used for system timer interrupts
huge if you take a look at it with objdump.

Later on we might want to split the posted bit check into a separate
inline function, and then you can implement this for the device
driver where things are more likely to go wrong with more complicated
use scenarios.

Regards,

Tony


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -254,9 +259,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>  static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>  						int posted)
>  {
> -	if (posted)
> -		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> -			cpu_relax();
> +	int i = 0;
> +
> +	if (posted) {
> +		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> +						, MAX_WRITE_PEND_WAIT, i);
> +
> +		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> +			pr_err("Read timeout!\n");
> +	}
>  
>  	return __raw_readl(timer->func_base + (reg & 0xff));
>  }
> @@ -264,9 +275,15 @@ static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>  static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
>  					u32 reg, u32 val, int posted)
>  {
> -	if (posted)
> -		while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> -			cpu_relax();
> +	int i = 0;
> +
> +	if (posted) {
> +		omap_test_timeout(!(__raw_readl(timer->pend) & (reg >> WPSHIFT))
> +						, MAX_WRITE_PEND_WAIT, i);
> +
> +		if (WARN_ON_ONCE(i == MAX_WRITE_PEND_WAIT))
> +			pr_err("Write timeout!\n");
> +	}
>  
>  	__raw_writel(val, timer->func_base + (reg & 0xff));
>  }

Let's leave out these changes for now, they make the
omap2_gp_timer_set_next_event used for system timer interrupts
huge if you take a look at it with objdump.

Later on we might want to split the posted bit check into a separate
inline function, and then you can implement this for the device
driver where things are more likely to go wrong with more complicated
use scenarios.

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-09-22  1:00     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: Tarun Kanti DebBarma; +Cc: linux-omap, khilman, linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -347,15 +346,16 @@ static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
>  	if (l & OMAP_TIMER_CTRL_ST) {
>  		l &= ~0x1;
>  		__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(timer, OMAP_TIMER_CTRL_REG, posted);
> -		/*
> -		 * Wait for functional clock period x 3.5 to make sure that
> -		 * timer is stopped
> -		 */
> -		udelay(3500000 / rate + 1);
> -#endif
> +		if (is_omap2) {
> +			/* Readback to make sure write has completed */
> +			__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
> +			 */
> +			udelay(3500000 / rate + 1);
> +		}
>  	}
>  
>  	/* Ack possibly pending interrupt */

I've left out this is_omap2 change as it really does not improve anything.
Instead it just makes __omap_dm_timer_stop inline function more complex.

I've also folded in the spinlock fixes in patch 10 into this patch.

Updated patch below.

Tony


From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:20 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
[tony@atomide.com: folded in spinlock changes, left out is_omap2]
Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index b2829ee..9c2f588 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -478,3 +478,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);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 92d5aff..6019208 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,120 +36,22 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/slab.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
-	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
-	"sys_ck",
-	"func_32k_ck",
-	"alt_ck",
-	NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers			NULL
-#define omap2_dm_timer_count		0
-#define omap2_dm_source_names		NULL
-#define omap2_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
-	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
-	"sys_ck",
-	"omap_32k_fck",
-	NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
-
-#else
-#define omap3_dm_timers			NULL
-#define omap3_dm_timer_count		0
-#define omap3_dm_source_names		NULL
-#define omap3_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
-	{ .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
-	{ .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
-	{ .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
-	{ .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
-	{ .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
-	{ .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
-	{ .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
-	{ .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
-	{ .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
-	{ .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
-	"sys_clkin_ck",
-	"sys_32k_ck",
-	NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+#include <linux/err.h>
 
-#else
-#define omap4_dm_timers			NULL
-#define omap4_dm_timer_count		0
-#define omap4_dm_source_names		NULL
-#define omap4_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
 
-static spinlock_t dm_timer_lock;
 static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
 
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which read operation to perform
+ * @reg:        lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
@@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 	return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which write operation is to perform
+ * @reg:        lowest byte holds the register offset
+ * @value:      data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
  */
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 						u32 value)
@@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-	int autoidle = 0, wakeup = 0;
-
-	if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
-	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
-	/* Enable autoidle on OMAP2+ */
-	if (cpu_class_is_omap2())
-		autoidle = 1;
-
-	/*
-	 * Enable wake-up on OMAP2 CPUs.
-	 */
-	if (cpu_class_is_omap2())
-		wakeup = 1;
 
-	__omap_dm_timer_reset(timer, autoidle, wakeup);
+	__omap_dm_timer_reset(timer, 0, 0);
 	timer->posted = 1;
 }
 
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	int ret;
+
+	timer->fclk = clk_get(&timer->pdev->dev, "fck");
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+		timer->fclk = NULL;
+		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+		return -EINVAL;
+	}
+
 	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
+
+	if (pdata->needs_manual_reset)
+		omap_dm_timer_reset(timer);
+
+	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+	timer->posted = 1;
+	return ret;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
 {
-	struct omap_dm_timer *timer = NULL;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
-	int i;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	for (i = 0; i < dm_timer_count; i++) {
-		if (dm_timers[i].reserved)
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->reserved)
 			continue;
 
-		timer = &dm_timers[i];
+		timer = t;
 		timer->reserved = 1;
 		break;
 	}
+
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	if (timer != NULL)
-		omap_dm_timer_prepare(timer);
+	if (!timer)
+		pr_debug("%s: timer request failed!\n", __func__);
 
 	return timer;
 }
@@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 
 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
-	struct omap_dm_timer *timer;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
-		spin_unlock_irqrestore(&dm_timer_lock, flags);
-		printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
-		       __FILE__, __LINE__, __func__, id);
-		dump_stack();
-		return NULL;
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->pdev->id == id && !t->reserved) {
+			timer = t;
+			timer->reserved = 1;
+			break;
+		}
 	}
 
-	timer = &dm_timers[id-1];
-	timer->reserved = 1;
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	omap_dm_timer_prepare(timer);
+	if (!timer)
+		pr_debug("%s: timer%d request failed!\n", __func__, id);
 
 	return timer;
 }
@@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
 	omap_dm_timer_disable(timer);
+	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
 	timer->reserved = 0;
@@ -278,15 +202,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_enable(timer->fclk);
 		clk_enable(timer->iclk);
 	}
-#endif
 
 	timer->enabled = 1;
 }
@@ -294,15 +218,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_disable(timer->iclk);
 		clk_disable(timer->fclk);
 	}
-#endif
 
 	timer->enabled = 0;
 }
@@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-	int i;
+	int i = 0;
+	struct omap_dm_timer *timer = NULL;
+	unsigned long flags;
 
 	/* If ARMXOR cannot be idled this function call is unnecessary */
 	if (!(inputmask & (1 << 1)))
 		return inputmask;
 
 	/* If any active timer is using ARMXOR return modified mask */
-	for (i = 0; i < dm_timer_count; i++) {
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		u32 l;
 
-		l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 		if (l & OMAP_TIMER_CTRL_ST) {
 			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 				inputmask &= ~(1 << 1);
 			else
 				inputmask &= ~(1 << 2);
 		}
+		i++;
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	return inputmask;
 }
@@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	rate = clk_get_rate(timer->fclk);
-#endif
+	if (!pdata->needs_manual_reset)
+		rate = clk_get_rate(timer->fclk);
 
 	__omap_dm_timer_stop(timer, timer->posted, rate);
 }
@@ -395,15 +324,17 @@ 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;
+
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	return __omap_dm_timer_set_source(timer->fclk,
-						dm_source_clocks[source]);
-#else
-	return 0;
-#endif
+	omap_dm_timer_disable(timer);
+	ret = pdata->set_timer_src(timer->pdev, source);
+	omap_dm_timer_enable(timer);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
@@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
 int omap_dm_timers_active(void)
 {
-	int i;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		struct omap_dm_timer *timer;
-
-		timer = &dm_timers[i];
+	struct omap_dm_timer *timer;
 
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		if (!timer->enabled)
 			continue;
 
@@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
-	__omap_dm_timer_init_regs(timer);
 
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -675,73 +601,3 @@ 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;
-	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
-
-	if (!cpu_class_is_omap2())
-		return -ENODEV;
-
-	spin_lock_init(&dm_timer_lock);
-
-	if (cpu_is_omap24xx()) {
-		dm_timers = omap2_dm_timers;
-		dm_timer_count = omap2_dm_timer_count;
-		dm_source_names = omap2_dm_source_names;
-		dm_source_clocks = omap2_dm_source_clocks;
-	} else if (cpu_is_omap34xx()) {
-		dm_timers = omap3_dm_timers;
-		dm_timer_count = omap3_dm_timer_count;
-		dm_source_names = omap3_dm_source_names;
-		dm_source_clocks = omap3_dm_source_clocks;
-	} else if (cpu_is_omap44xx()) {
-		dm_timers = omap4_dm_timers;
-		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())
-		for (i = 0; dm_source_names[i] != NULL; i++)
-			dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
-
-	if (cpu_is_omap243x())
-		dm_timers[0].phys_base = 0x49018000;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		timer = &dm_timers[i];
-
-		/* Static mapping, never released */
-		timer->io_base = ioremap(timer->phys_base, map_size);
-		BUG_ON(!timer->io_base);
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-		if (cpu_class_is_omap2()) {
-			char clk_name[16];
-			sprintf(clk_name, "gpt%d_ick", i + 1);
-			timer->iclk = clk_get(NULL, clk_name);
-			sprintf(clk_name, "gpt%d_fck", i + 1);
-			timer->fclk = clk_get(NULL, clk_name);
-		}
-
-		/* One or two timers may be set up early for sys_timer */
-		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_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 98f186e..2ac7538 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -231,9 +231,8 @@ struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
 	int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
 	struct clk *iclk, *fclk;
-#endif
+
 	void __iomem	*io_base;
 	void __iomem	*sys_stat;	/* TISTAT timer status */
 	void __iomem	*irq_stat;	/* TISR/IRQSTATUS interrupt status */
@@ -251,7 +250,7 @@ struct omap_dm_timer {
 };
 
 extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
@ 2011-09-22  1:00     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-22  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
> @@ -347,15 +346,16 @@ static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
>  	if (l & OMAP_TIMER_CTRL_ST) {
>  		l &= ~0x1;
>  		__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(timer, OMAP_TIMER_CTRL_REG, posted);
> -		/*
> -		 * Wait for functional clock period x 3.5 to make sure that
> -		 * timer is stopped
> -		 */
> -		udelay(3500000 / rate + 1);
> -#endif
> +		if (is_omap2) {
> +			/* Readback to make sure write has completed */
> +			__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
> +			 */
> +			udelay(3500000 / rate + 1);
> +		}
>  	}
>  
>  	/* Ack possibly pending interrupt */

I've left out this is_omap2 change as it really does not improve anything.
Instead it just makes __omap_dm_timer_stop inline function more complex.

I've also folded in the spinlock fixes in patch 10 into this patch.

Updated patch below.

Tony


From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Tue, 20 Sep 2011 17:00:20 +0530
Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver

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.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Acked-by: Cousson, Benoit <b-cousson@ti.com>
[tony at atomide.com: folded in spinlock changes, left out is_omap2]
Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index b2829ee..9c2f588 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -478,3 +478,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);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 92d5aff..6019208 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,120 +36,22 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/slab.h>
-#include <mach/hardware.h>
-#include <plat/dmtimer.h>
-#include <mach/irqs.h>
-
-static int dm_timer_count;
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct omap_dm_timer omap2_dm_timers[] = {
-	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
-};
-
-static const char *omap2_dm_source_names[] __initdata = {
-	"sys_ck",
-	"func_32k_ck",
-	"alt_ck",
-	NULL
-};
-
-static struct clk *omap2_dm_source_clocks[3];
-static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
-
-#else
-#define omap2_dm_timers			NULL
-#define omap2_dm_timer_count		0
-#define omap2_dm_source_names		NULL
-#define omap2_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP2 */
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_dm_timer omap3_dm_timers[] = {
-	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
-	{ .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
-	{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
-	{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
-	{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
-	{ .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
-	{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
-	{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
-	{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
-	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
-	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-	{ .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
-};
-
-static const char *omap3_dm_source_names[] __initdata = {
-	"sys_ck",
-	"omap_32k_fck",
-	NULL
-};
-
-static struct clk *omap3_dm_source_clocks[2];
-static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
-
-#else
-#define omap3_dm_timers			NULL
-#define omap3_dm_timer_count		0
-#define omap3_dm_source_names		NULL
-#define omap3_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP3 */
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct omap_dm_timer omap4_dm_timers[] = {
-	{ .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
-	{ .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
-	{ .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
-	{ .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
-	{ .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
-	{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
-	{ .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
-	{ .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
-	{ .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
-	{ .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
-	{ .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
-};
-static const char *omap4_dm_source_names[] __initdata = {
-	"sys_clkin_ck",
-	"sys_32k_ck",
-	NULL
-};
-static struct clk *omap4_dm_source_clocks[2];
-static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+#include <linux/err.h>
 
-#else
-#define omap4_dm_timers			NULL
-#define omap4_dm_timer_count		0
-#define omap4_dm_source_names		NULL
-#define omap4_dm_source_clocks		NULL
-#endif	/* CONFIG_ARCH_OMAP4 */
-
-static struct omap_dm_timer *dm_timers;
-static const char **dm_source_names;
-static struct clk **dm_source_clocks;
+#include <plat/dmtimer.h>
 
-static spinlock_t dm_timer_lock;
 static LIST_HEAD(omap_timer_list);
+static DEFINE_SPINLOCK(dm_timer_lock);
 
-/*
- * Reads timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode write pending bit must be
- * checked. Otherwise a read of a non completed write will produce an error.
+/**
+ * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which read operation to perform
+ * @reg:        lowest byte holds the register offset
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode write
+ * pending bit must be checked. Otherwise a read of a non completed write
+ * will produce an error.
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
@@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 	return __omap_dm_timer_read(timer, reg, timer->posted);
 }
 
-/*
- * Writes timer registers in posted and non-posted mode. The posted mode bit
- * is encoded in reg. Note that in posted mode the write pending bit must be
- * checked. Otherwise a write on a register which has a pending write will be
- * lost.
+/**
+ * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
+ * @timer:      timer pointer over which write operation is to perform
+ * @reg:        lowest byte holds the register offset
+ * @value:      data to write into the register
+ *
+ * The posted mode bit is encoded in reg. Note that in posted mode the write
+ * pending bit must be checked. Otherwise a write on a register which has a
+ * pending write will be lost.
  */
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 						u32 value)
@@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-	int autoidle = 0, wakeup = 0;
-
-	if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
-	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
-	/* Enable autoidle on OMAP2+ */
-	if (cpu_class_is_omap2())
-		autoidle = 1;
-
-	/*
-	 * Enable wake-up on OMAP2 CPUs.
-	 */
-	if (cpu_class_is_omap2())
-		wakeup = 1;
 
-	__omap_dm_timer_reset(timer, autoidle, wakeup);
+	__omap_dm_timer_reset(timer, 0, 0);
 	timer->posted = 1;
 }
 
-void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+	int ret;
+
+	timer->fclk = clk_get(&timer->pdev->dev, "fck");
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
+		timer->fclk = NULL;
+		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
+		return -EINVAL;
+	}
+
 	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
+
+	if (pdata->needs_manual_reset)
+		omap_dm_timer_reset(timer);
+
+	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+	timer->posted = 1;
+	return ret;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
 {
-	struct omap_dm_timer *timer = NULL;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
-	int i;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	for (i = 0; i < dm_timer_count; i++) {
-		if (dm_timers[i].reserved)
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->reserved)
 			continue;
 
-		timer = &dm_timers[i];
+		timer = t;
 		timer->reserved = 1;
 		break;
 	}
+
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	if (timer != NULL)
-		omap_dm_timer_prepare(timer);
+	if (!timer)
+		pr_debug("%s: timer request failed!\n", __func__);
 
 	return timer;
 }
@@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 
 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
-	struct omap_dm_timer *timer;
+	struct omap_dm_timer *timer = NULL, *t;
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&dm_timer_lock, flags);
-	if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
-		spin_unlock_irqrestore(&dm_timer_lock, flags);
-		printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
-		       __FILE__, __LINE__, __func__, id);
-		dump_stack();
-		return NULL;
+	list_for_each_entry(t, &omap_timer_list, node) {
+		if (t->pdev->id == id && !t->reserved) {
+			timer = t;
+			timer->reserved = 1;
+			break;
+		}
 	}
 
-	timer = &dm_timers[id-1];
-	timer->reserved = 1;
+	if (timer) {
+		ret = omap_dm_timer_prepare(timer);
+		if (ret) {
+			timer->reserved = 0;
+			timer = NULL;
+		}
+	}
 	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
-	omap_dm_timer_prepare(timer);
+	if (!timer)
+		pr_debug("%s: timer%d request failed!\n", __func__, id);
 
 	return timer;
 }
@@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_enable(timer);
-	omap_dm_timer_reset(timer);
 	omap_dm_timer_disable(timer);
+	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
 	timer->reserved = 0;
@@ -278,15 +202,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_enable(timer->fclk);
 		clk_enable(timer->iclk);
 	}
-#endif
 
 	timer->enabled = 1;
 }
@@ -294,15 +218,15 @@ 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;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	if (cpu_class_is_omap2()) {
+	if (!pdata->needs_manual_reset) {
 		clk_disable(timer->iclk);
 		clk_disable(timer->fclk);
 	}
-#endif
 
 	timer->enabled = 0;
 }
@@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-	int i;
+	int i = 0;
+	struct omap_dm_timer *timer = NULL;
+	unsigned long flags;
 
 	/* If ARMXOR cannot be idled this function call is unnecessary */
 	if (!(inputmask & (1 << 1)))
 		return inputmask;
 
 	/* If any active timer is using ARMXOR return modified mask */
-	for (i = 0; i < dm_timer_count; i++) {
+	spin_lock_irqsave(&dm_timer_lock, flags);
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		u32 l;
 
-		l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 		if (l & OMAP_TIMER_CTRL_ST) {
 			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 				inputmask &= ~(1 << 1);
 			else
 				inputmask &= ~(1 << 2);
 		}
+		i++;
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	return inputmask;
 }
@@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
+	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	rate = clk_get_rate(timer->fclk);
-#endif
+	if (!pdata->needs_manual_reset)
+		rate = clk_get_rate(timer->fclk);
 
 	__omap_dm_timer_stop(timer, timer->posted, rate);
 }
@@ -395,15 +324,17 @@ 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;
+
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	return __omap_dm_timer_set_source(timer->fclk,
-						dm_source_clocks[source]);
-#else
-	return 0;
-#endif
+	omap_dm_timer_disable(timer);
+	ret = pdata->set_timer_src(timer->pdev, source);
+	omap_dm_timer_enable(timer);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
@@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
 int omap_dm_timers_active(void)
 {
-	int i;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		struct omap_dm_timer *timer;
-
-		timer = &dm_timers[i];
+	struct omap_dm_timer *timer;
 
+	list_for_each_entry(timer, &omap_timer_list, node) {
 		if (!timer->enabled)
 			continue;
 
@@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->id = pdev->id;
 	timer->irq = irq->start;
 	timer->pdev = pdev;
-	__omap_dm_timer_init_regs(timer);
 
 	/* add the timer element to the list */
 	spin_lock_irqsave(&dm_timer_lock, flags);
@@ -675,73 +601,3 @@ 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;
-	int i, map_size = SZ_8K;	/* Module 4KB + L4 4KB except on omap1 */
-
-	if (!cpu_class_is_omap2())
-		return -ENODEV;
-
-	spin_lock_init(&dm_timer_lock);
-
-	if (cpu_is_omap24xx()) {
-		dm_timers = omap2_dm_timers;
-		dm_timer_count = omap2_dm_timer_count;
-		dm_source_names = omap2_dm_source_names;
-		dm_source_clocks = omap2_dm_source_clocks;
-	} else if (cpu_is_omap34xx()) {
-		dm_timers = omap3_dm_timers;
-		dm_timer_count = omap3_dm_timer_count;
-		dm_source_names = omap3_dm_source_names;
-		dm_source_clocks = omap3_dm_source_clocks;
-	} else if (cpu_is_omap44xx()) {
-		dm_timers = omap4_dm_timers;
-		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())
-		for (i = 0; dm_source_names[i] != NULL; i++)
-			dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
-
-	if (cpu_is_omap243x())
-		dm_timers[0].phys_base = 0x49018000;
-
-	for (i = 0; i < dm_timer_count; i++) {
-		timer = &dm_timers[i];
-
-		/* Static mapping, never released */
-		timer->io_base = ioremap(timer->phys_base, map_size);
-		BUG_ON(!timer->io_base);
-
-#ifdef CONFIG_ARCH_OMAP2PLUS
-		if (cpu_class_is_omap2()) {
-			char clk_name[16];
-			sprintf(clk_name, "gpt%d_ick", i + 1);
-			timer->iclk = clk_get(NULL, clk_name);
-			sprintf(clk_name, "gpt%d_fck", i + 1);
-			timer->fclk = clk_get(NULL, clk_name);
-		}
-
-		/* One or two timers may be set up early for sys_timer */
-		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_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 98f186e..2ac7538 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -231,9 +231,8 @@ struct omap_dm_timer {
 	unsigned long phys_base;
 	int id;
 	int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
 	struct clk *iclk, *fclk;
-#endif
+
 	void __iomem	*io_base;
 	void __iomem	*sys_stat;	/* TISTAT timer status */
 	void __iomem	*irq_stat;	/* TISR/IRQSTATUS interrupt status */
@@ -251,7 +250,7 @@ struct omap_dm_timer {
 };
 
 extern u32 sys_timer_reserved;
-void omap_dm_timer_prepare(struct omap_dm_timer *timer);
+int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 						int posted)

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
  2011-09-22  1:00     ` Tony Lindgren
@ 2011-09-22  5:53       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:53 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

> Let's leave out these changes for now, they make the
> omap2_gp_timer_set_next_event used for system timer interrupts
> huge if you take a look at it with objdump.
>
> Later on we might want to split the posted bit check into a separate
> inline function, and then you can implement this for the device
> driver where things are more likely to go wrong with more complicated
> use scenarios.
Alright.
--
Tarun
>
> Regards,
>
> Tony
>
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
@ 2011-09-22  5:53       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:53 UTC (permalink / raw)
  To: linux-arm-kernel

> Let's leave out these changes for now, they make the
> omap2_gp_timer_set_next_event used for system timer interrupts
> huge if you take a look at it with objdump.
>
> Later on we might want to split the posted bit check into a separate
> inline function, and then you can implement this for the device
> driver where things are more likely to go wrong with more complicated
> use scenarios.
Alright.
--
Tarun
>
> Regards,
>
> Tony
>
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
  2011-09-22  1:00     ` Tony Lindgren
@ 2011-09-22  5:57       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:57 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

[...]
>>
>>       /* Ack possibly pending interrupt */
>
> I've left out this is_omap2 change as it really does not improve anything.
> Instead it just makes __omap_dm_timer_stop inline function more complex.
Agreed.

>
> I've also folded in the spinlock fixes in patch 10 into this patch.
Ok, thanks.
--
Tarun
>
> Updated patch below.
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:20 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver
>
> 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.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Acked-by: Cousson, Benoit <b-cousson@ti.com>
> [tony@atomide.com: folded in spinlock changes, left out is_omap2]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index b2829ee..9c2f588 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -478,3 +478,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);
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index 92d5aff..6019208 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -36,120 +36,22 @@
>  */
>
>  #include <linux/io.h>
> -#include <linux/module.h>
>  #include <linux/slab.h>
> -#include <mach/hardware.h>
> -#include <plat/dmtimer.h>
> -#include <mach/irqs.h>
> -
> -static int dm_timer_count;
> -
> -#ifdef CONFIG_ARCH_OMAP2
> -static struct omap_dm_timer omap2_dm_timers[] = {
> -       { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
> -       { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
> -       { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
> -       { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
> -       { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
> -       { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
> -       { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
> -       { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
> -       { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
> -       { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> -       { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> -       { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
> -};
> -
> -static const char *omap2_dm_source_names[] __initdata = {
> -       "sys_ck",
> -       "func_32k_ck",
> -       "alt_ck",
> -       NULL
> -};
> -
> -static struct clk *omap2_dm_source_clocks[3];
> -static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
> -
> -#else
> -#define omap2_dm_timers                        NULL
> -#define omap2_dm_timer_count           0
> -#define omap2_dm_source_names          NULL
> -#define omap2_dm_source_clocks         NULL
> -#endif /* CONFIG_ARCH_OMAP2 */
> -
> -#ifdef CONFIG_ARCH_OMAP3
> -static struct omap_dm_timer omap3_dm_timers[] = {
> -       { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
> -       { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
> -       { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
> -       { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
> -       { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
> -       { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
> -       { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
> -       { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
> -       { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
> -       { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> -       { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> -       { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
> -};
> -
> -static const char *omap3_dm_source_names[] __initdata = {
> -       "sys_ck",
> -       "omap_32k_fck",
> -       NULL
> -};
> -
> -static struct clk *omap3_dm_source_clocks[2];
> -static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
> -
> -#else
> -#define omap3_dm_timers                        NULL
> -#define omap3_dm_timer_count           0
> -#define omap3_dm_source_names          NULL
> -#define omap3_dm_source_clocks         NULL
> -#endif /* CONFIG_ARCH_OMAP3 */
> -
> -#ifdef CONFIG_ARCH_OMAP4
> -static struct omap_dm_timer omap4_dm_timers[] = {
> -       { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
> -       { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
> -       { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
> -       { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
> -       { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
> -       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
> -       { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
> -       { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
> -       { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
> -       { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
> -       { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
> -       { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
> -};
> -static const char *omap4_dm_source_names[] __initdata = {
> -       "sys_clkin_ck",
> -       "sys_32k_ck",
> -       NULL
> -};
> -static struct clk *omap4_dm_source_clocks[2];
> -static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
> +#include <linux/err.h>
>
> -#else
> -#define omap4_dm_timers                        NULL
> -#define omap4_dm_timer_count           0
> -#define omap4_dm_source_names          NULL
> -#define omap4_dm_source_clocks         NULL
> -#endif /* CONFIG_ARCH_OMAP4 */
> -
> -static struct omap_dm_timer *dm_timers;
> -static const char **dm_source_names;
> -static struct clk **dm_source_clocks;
> +#include <plat/dmtimer.h>
>
> -static spinlock_t dm_timer_lock;
>  static LIST_HEAD(omap_timer_list);
> +static DEFINE_SPINLOCK(dm_timer_lock);
>
> -/*
> - * Reads timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode write pending bit must be
> - * checked. Otherwise a read of a non completed write will produce an error.
> +/**
> + * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
> + * @timer:      timer pointer over which read operation to perform
> + * @reg:        lowest byte holds the register offset
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode write
> + * pending bit must be checked. Otherwise a read of a non completed write
> + * will produce an error.
>  */
>  static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
>  {
> @@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
>        return __omap_dm_timer_read(timer, reg, timer->posted);
>  }
>
> -/*
> - * Writes timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode the write pending bit must be
> - * checked. Otherwise a write on a register which has a pending write will be
> - * lost.
> +/**
> + * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
> + * @timer:      timer pointer over which write operation is to perform
> + * @reg:        lowest byte holds the register offset
> + * @value:      data to write into the register
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode the write
> + * pending bit must be checked. Otherwise a write on a register which has a
> + * pending write will be lost.
>  */
>  static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
>                                                u32 value)
> @@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
>  static void omap_dm_timer_reset(struct omap_dm_timer *timer)
>  {
> -       int autoidle = 0, wakeup = 0;
> -
> -       if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
> +       if (timer->pdev->id != 1) {
>                omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
>                omap_dm_timer_wait_for_reset(timer);
>        }
> -       omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> -
> -       /* Enable autoidle on OMAP2+ */
> -       if (cpu_class_is_omap2())
> -               autoidle = 1;
> -
> -       /*
> -        * Enable wake-up on OMAP2 CPUs.
> -        */
> -       if (cpu_class_is_omap2())
> -               wakeup = 1;
>
> -       __omap_dm_timer_reset(timer, autoidle, wakeup);
> +       __omap_dm_timer_reset(timer, 0, 0);
>        timer->posted = 1;
>  }
>
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer)
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer)
>  {
> +       struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> +       int ret;
> +
> +       timer->fclk = clk_get(&timer->pdev->dev, "fck");
> +       if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
> +               timer->fclk = NULL;
> +               dev_err(&timer->pdev->dev, ": No fclk handle.\n");
> +               return -EINVAL;
> +       }
> +
>        omap_dm_timer_enable(timer);
> -       omap_dm_timer_reset(timer);
> +
> +       if (pdata->needs_manual_reset)
> +               omap_dm_timer_reset(timer);
> +
> +       ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> +
> +       timer->posted = 1;
> +       return ret;
>  }
>
>  struct omap_dm_timer *omap_dm_timer_request(void)
>  {
> -       struct omap_dm_timer *timer = NULL;
> +       struct omap_dm_timer *timer = NULL, *t;
>        unsigned long flags;
> -       int i;
> +       int ret = 0;
>
>        spin_lock_irqsave(&dm_timer_lock, flags);
> -       for (i = 0; i < dm_timer_count; i++) {
> -               if (dm_timers[i].reserved)
> +       list_for_each_entry(t, &omap_timer_list, node) {
> +               if (t->reserved)
>                        continue;
>
> -               timer = &dm_timers[i];
> +               timer = t;
>                timer->reserved = 1;
>                break;
>        }
> +
> +       if (timer) {
> +               ret = omap_dm_timer_prepare(timer);
> +               if (ret) {
> +                       timer->reserved = 0;
> +                       timer = NULL;
> +               }
> +       }
>        spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> -       if (timer != NULL)
> -               omap_dm_timer_prepare(timer);
> +       if (!timer)
> +               pr_debug("%s: timer request failed!\n", __func__);
>
>        return timer;
>  }
> @@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
>
>  struct omap_dm_timer *omap_dm_timer_request_specific(int id)
>  {
> -       struct omap_dm_timer *timer;
> +       struct omap_dm_timer *timer = NULL, *t;
>        unsigned long flags;
> +       int ret = 0;
>
>        spin_lock_irqsave(&dm_timer_lock, flags);
> -       if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
> -               spin_unlock_irqrestore(&dm_timer_lock, flags);
> -               printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
> -                      __FILE__, __LINE__, __func__, id);
> -               dump_stack();
> -               return NULL;
> +       list_for_each_entry(t, &omap_timer_list, node) {
> +               if (t->pdev->id == id && !t->reserved) {
> +                       timer = t;
> +                       timer->reserved = 1;
> +                       break;
> +               }
>        }
>
> -       timer = &dm_timers[id-1];
> -       timer->reserved = 1;
> +       if (timer) {
> +               ret = omap_dm_timer_prepare(timer);
> +               if (ret) {
> +                       timer->reserved = 0;
> +                       timer = NULL;
> +               }
> +       }
>        spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> -       omap_dm_timer_prepare(timer);
> +       if (!timer)
> +               pr_debug("%s: timer%d request failed!\n", __func__, id);
>
>        return timer;
>  }
> @@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
>  void omap_dm_timer_free(struct omap_dm_timer *timer)
>  {
> -       omap_dm_timer_enable(timer);
> -       omap_dm_timer_reset(timer);
>        omap_dm_timer_disable(timer);
> +       clk_put(timer->fclk);
>
>        WARN_ON(!timer->reserved);
>        timer->reserved = 0;
> @@ -278,15 +202,15 @@ 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;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> -       if (cpu_class_is_omap2()) {
> +       if (!pdata->needs_manual_reset) {
>                clk_enable(timer->fclk);
>                clk_enable(timer->iclk);
>        }
> -#endif
>
>        timer->enabled = 1;
>  }
> @@ -294,15 +218,15 @@ 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;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> -       if (cpu_class_is_omap2()) {
> +       if (!pdata->needs_manual_reset) {
>                clk_disable(timer->iclk);
>                clk_disable(timer->fclk);
>        }
> -#endif
>
>        timer->enabled = 0;
>  }
> @@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
>  */
>  __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
>  {
> -       int i;
> +       int i = 0;
> +       struct omap_dm_timer *timer = NULL;
> +       unsigned long flags;
>
>        /* If ARMXOR cannot be idled this function call is unnecessary */
>        if (!(inputmask & (1 << 1)))
>                return inputmask;
>
>        /* If any active timer is using ARMXOR return modified mask */
> -       for (i = 0; i < dm_timer_count; i++) {
> +       spin_lock_irqsave(&dm_timer_lock, flags);
> +       list_for_each_entry(timer, &omap_timer_list, node) {
>                u32 l;
>
> -               l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
> +               l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>                if (l & OMAP_TIMER_CTRL_ST) {
>                        if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
>                                inputmask &= ~(1 << 1);
>                        else
>                                inputmask &= ~(1 << 2);
>                }
> +               i++;
>        }
> +       spin_unlock_irqrestore(&dm_timer_lock, flags);
>
>        return inputmask;
>  }
> @@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
>  void omap_dm_timer_stop(struct omap_dm_timer *timer)
>  {
>        unsigned long rate = 0;
> +       struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> -       rate = clk_get_rate(timer->fclk);
> -#endif
> +       if (!pdata->needs_manual_reset)
> +               rate = clk_get_rate(timer->fclk);
>
>        __omap_dm_timer_stop(timer, timer->posted, rate);
>  }
> @@ -395,15 +324,17 @@ 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;
> +
>        if (source < 0 || source >= 3)
>                return -EINVAL;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> -       return __omap_dm_timer_set_source(timer->fclk,
> -                                               dm_source_clocks[source]);
> -#else
> -       return 0;
> -#endif
> +       omap_dm_timer_disable(timer);
> +       ret = pdata->set_timer_src(timer->pdev, source);
> +       omap_dm_timer_enable(timer);
> +
> +       return ret;
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
>
> @@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
>  int omap_dm_timers_active(void)
>  {
> -       int i;
> -
> -       for (i = 0; i < dm_timer_count; i++) {
> -               struct omap_dm_timer *timer;
> -
> -               timer = &dm_timers[i];
> +       struct omap_dm_timer *timer;
>
> +       list_for_each_entry(timer, &omap_timer_list, node) {
>                if (!timer->enabled)
>                        continue;
>
> @@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>        timer->id = pdev->id;
>        timer->irq = irq->start;
>        timer->pdev = pdev;
> -       __omap_dm_timer_init_regs(timer);
>
>        /* add the timer element to the list */
>        spin_lock_irqsave(&dm_timer_lock, flags);
> @@ -675,73 +601,3 @@ 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;
> -       int i, map_size = SZ_8K;        /* Module 4KB + L4 4KB except on omap1 */
> -
> -       if (!cpu_class_is_omap2())
> -               return -ENODEV;
> -
> -       spin_lock_init(&dm_timer_lock);
> -
> -       if (cpu_is_omap24xx()) {
> -               dm_timers = omap2_dm_timers;
> -               dm_timer_count = omap2_dm_timer_count;
> -               dm_source_names = omap2_dm_source_names;
> -               dm_source_clocks = omap2_dm_source_clocks;
> -       } else if (cpu_is_omap34xx()) {
> -               dm_timers = omap3_dm_timers;
> -               dm_timer_count = omap3_dm_timer_count;
> -               dm_source_names = omap3_dm_source_names;
> -               dm_source_clocks = omap3_dm_source_clocks;
> -       } else if (cpu_is_omap44xx()) {
> -               dm_timers = omap4_dm_timers;
> -               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())
> -               for (i = 0; dm_source_names[i] != NULL; i++)
> -                       dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
> -
> -       if (cpu_is_omap243x())
> -               dm_timers[0].phys_base = 0x49018000;
> -
> -       for (i = 0; i < dm_timer_count; i++) {
> -               timer = &dm_timers[i];
> -
> -               /* Static mapping, never released */
> -               timer->io_base = ioremap(timer->phys_base, map_size);
> -               BUG_ON(!timer->io_base);
> -
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> -               if (cpu_class_is_omap2()) {
> -                       char clk_name[16];
> -                       sprintf(clk_name, "gpt%d_ick", i + 1);
> -                       timer->iclk = clk_get(NULL, clk_name);
> -                       sprintf(clk_name, "gpt%d_fck", i + 1);
> -                       timer->fclk = clk_get(NULL, clk_name);
> -               }
> -
> -               /* One or two timers may be set up early for sys_timer */
> -               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_initcall(omap_dm_timer_init);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 98f186e..2ac7538 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -231,9 +231,8 @@ struct omap_dm_timer {
>        unsigned long phys_base;
>        int id;
>        int irq;
> -#ifdef CONFIG_ARCH_OMAP2PLUS
>        struct clk *iclk, *fclk;
> -#endif
> +
>        void __iomem    *io_base;
>        void __iomem    *sys_stat;      /* TISTAT timer status */
>        void __iomem    *irq_stat;      /* TISR/IRQSTATUS interrupt status */
> @@ -251,7 +250,7 @@ struct omap_dm_timer {
>  };
>
>  extern u32 sys_timer_reserved;
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer);
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
>  static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>                                                int posted)
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
@ 2011-09-22  5:57       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:57 UTC (permalink / raw)
  To: linux-arm-kernel

[...]
>>
>> ? ? ? /* Ack possibly pending interrupt */
>
> I've left out this is_omap2 change as it really does not improve anything.
> Instead it just makes __omap_dm_timer_stop inline function more complex.
Agreed.

>
> I've also folded in the spinlock fixes in patch 10 into this patch.
Ok, thanks.
--
Tarun
>
> Updated patch below.
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:20 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver
>
> 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.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Acked-by: Cousson, Benoit <b-cousson@ti.com>
> [tony at atomide.com: folded in spinlock changes, left out is_omap2]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index b2829ee..9c2f588 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -478,3 +478,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);
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index 92d5aff..6019208 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -36,120 +36,22 @@
> ?*/
>
> ?#include <linux/io.h>
> -#include <linux/module.h>
> ?#include <linux/slab.h>
> -#include <mach/hardware.h>
> -#include <plat/dmtimer.h>
> -#include <mach/irqs.h>
> -
> -static int dm_timer_count;
> -
> -#ifdef CONFIG_ARCH_OMAP2
> -static struct omap_dm_timer omap2_dm_timers[] = {
> - ? ? ? { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
> - ? ? ? { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
> - ? ? ? { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
> - ? ? ? { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
> - ? ? ? { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
> - ? ? ? { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
> - ? ? ? { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
> - ? ? ? { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
> - ? ? ? { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> - ? ? ? { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
> -};
> -
> -static const char *omap2_dm_source_names[] __initdata = {
> - ? ? ? "sys_ck",
> - ? ? ? "func_32k_ck",
> - ? ? ? "alt_ck",
> - ? ? ? NULL
> -};
> -
> -static struct clk *omap2_dm_source_clocks[3];
> -static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
> -
> -#else
> -#define omap2_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap2_dm_timer_count ? ? ? ? ? 0
> -#define omap2_dm_source_names ? ? ? ? ?NULL
> -#define omap2_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP2 */
> -
> -#ifdef CONFIG_ARCH_OMAP3
> -static struct omap_dm_timer omap3_dm_timers[] = {
> - ? ? ? { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
> - ? ? ? { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
> - ? ? ? { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
> - ? ? ? { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
> - ? ? ? { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
> - ? ? ? { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
> - ? ? ? { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
> - ? ? ? { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
> - ? ? ? { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> - ? ? ? { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
> -};
> -
> -static const char *omap3_dm_source_names[] __initdata = {
> - ? ? ? "sys_ck",
> - ? ? ? "omap_32k_fck",
> - ? ? ? NULL
> -};
> -
> -static struct clk *omap3_dm_source_clocks[2];
> -static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
> -
> -#else
> -#define omap3_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap3_dm_timer_count ? ? ? ? ? 0
> -#define omap3_dm_source_names ? ? ? ? ?NULL
> -#define omap3_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP3 */
> -
> -#ifdef CONFIG_ARCH_OMAP4
> -static struct omap_dm_timer omap4_dm_timers[] = {
> - ? ? ? { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
> - ? ? ? { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
> - ? ? ? { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
> - ? ? ? { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
> - ? ? ? { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
> - ? ? ? { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
> - ? ? ? { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
> - ? ? ? { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
> - ? ? ? { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
> - ? ? ? { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
> -};
> -static const char *omap4_dm_source_names[] __initdata = {
> - ? ? ? "sys_clkin_ck",
> - ? ? ? "sys_32k_ck",
> - ? ? ? NULL
> -};
> -static struct clk *omap4_dm_source_clocks[2];
> -static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
> +#include <linux/err.h>
>
> -#else
> -#define omap4_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap4_dm_timer_count ? ? ? ? ? 0
> -#define omap4_dm_source_names ? ? ? ? ?NULL
> -#define omap4_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP4 */
> -
> -static struct omap_dm_timer *dm_timers;
> -static const char **dm_source_names;
> -static struct clk **dm_source_clocks;
> +#include <plat/dmtimer.h>
>
> -static spinlock_t dm_timer_lock;
> ?static LIST_HEAD(omap_timer_list);
> +static DEFINE_SPINLOCK(dm_timer_lock);
>
> -/*
> - * Reads timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode write pending bit must be
> - * checked. Otherwise a read of a non completed write will produce an error.
> +/**
> + * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
> + * @timer: ? ? ?timer pointer over which read operation to perform
> + * @reg: ? ? ? ?lowest byte holds the register offset
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode write
> + * pending bit must be checked. Otherwise a read of a non completed write
> + * will produce an error.
> ?*/
> ?static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ?{
> @@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ? ? ? ?return __omap_dm_timer_read(timer, reg, timer->posted);
> ?}
>
> -/*
> - * Writes timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode the write pending bit must be
> - * checked. Otherwise a write on a register which has a pending write will be
> - * lost.
> +/**
> + * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
> + * @timer: ? ? ?timer pointer over which write operation is to perform
> + * @reg: ? ? ? ?lowest byte holds the register offset
> + * @value: ? ? ?data to write into the register
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode the write
> + * pending bit must be checked. Otherwise a write on a register which has a
> + * pending write will be lost.
> ?*/
> ?static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 value)
> @@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
> ?static void omap_dm_timer_reset(struct omap_dm_timer *timer)
> ?{
> - ? ? ? int autoidle = 0, wakeup = 0;
> -
> - ? ? ? if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
> + ? ? ? if (timer->pdev->id != 1) {
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
> ? ? ? ? ? ? ? ?omap_dm_timer_wait_for_reset(timer);
> ? ? ? ?}
> - ? ? ? omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> -
> - ? ? ? /* Enable autoidle on OMAP2+ */
> - ? ? ? if (cpu_class_is_omap2())
> - ? ? ? ? ? ? ? autoidle = 1;
> -
> - ? ? ? /*
> - ? ? ? ?* Enable wake-up on OMAP2 CPUs.
> - ? ? ? ?*/
> - ? ? ? if (cpu_class_is_omap2())
> - ? ? ? ? ? ? ? wakeup = 1;
>
> - ? ? ? __omap_dm_timer_reset(timer, autoidle, wakeup);
> + ? ? ? __omap_dm_timer_reset(timer, 0, 0);
> ? ? ? ?timer->posted = 1;
> ?}
>
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer)
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer)
> ?{
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> + ? ? ? int ret;
> +
> + ? ? ? timer->fclk = clk_get(&timer->pdev->dev, "fck");
> + ? ? ? if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
> + ? ? ? ? ? ? ? timer->fclk = NULL;
> + ? ? ? ? ? ? ? dev_err(&timer->pdev->dev, ": No fclk handle.\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_enable(timer);
> - ? ? ? omap_dm_timer_reset(timer);
> +
> + ? ? ? if (pdata->needs_manual_reset)
> + ? ? ? ? ? ? ? omap_dm_timer_reset(timer);
> +
> + ? ? ? ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> +
> + ? ? ? timer->posted = 1;
> + ? ? ? return ret;
> ?}
>
> ?struct omap_dm_timer *omap_dm_timer_request(void)
> ?{
> - ? ? ? struct omap_dm_timer *timer = NULL;
> + ? ? ? struct omap_dm_timer *timer = NULL, *t;
> ? ? ? ?unsigned long flags;
> - ? ? ? int i;
> + ? ? ? int ret = 0;
>
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? if (dm_timers[i].reserved)
> + ? ? ? list_for_each_entry(t, &omap_timer_list, node) {
> + ? ? ? ? ? ? ? if (t->reserved)
> ? ? ? ? ? ? ? ? ? ? ? ?continue;
>
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> + ? ? ? ? ? ? ? timer = t;
> ? ? ? ? ? ? ? ?timer->reserved = 1;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
> +
> + ? ? ? if (timer) {
> + ? ? ? ? ? ? ? ret = omap_dm_timer_prepare(timer);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 0;
> + ? ? ? ? ? ? ? ? ? ? ? timer = NULL;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> ? ? ? ?spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> - ? ? ? if (timer != NULL)
> - ? ? ? ? ? ? ? omap_dm_timer_prepare(timer);
> + ? ? ? if (!timer)
> + ? ? ? ? ? ? ? pr_debug("%s: timer request failed!\n", __func__);
>
> ? ? ? ?return timer;
> ?}
> @@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
>
> ?struct omap_dm_timer *omap_dm_timer_request_specific(int id)
> ?{
> - ? ? ? struct omap_dm_timer *timer;
> + ? ? ? struct omap_dm_timer *timer = NULL, *t;
> ? ? ? ?unsigned long flags;
> + ? ? ? int ret = 0;
>
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> - ? ? ? if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
> - ? ? ? ? ? ? ? spin_unlock_irqrestore(&dm_timer_lock, flags);
> - ? ? ? ? ? ? ? printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
> - ? ? ? ? ? ? ? ? ? ? ?__FILE__, __LINE__, __func__, id);
> - ? ? ? ? ? ? ? dump_stack();
> - ? ? ? ? ? ? ? return NULL;
> + ? ? ? list_for_each_entry(t, &omap_timer_list, node) {
> + ? ? ? ? ? ? ? if (t->pdev->id == id && !t->reserved) {
> + ? ? ? ? ? ? ? ? ? ? ? timer = t;
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 1;
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? }
> ? ? ? ?}
>
> - ? ? ? timer = &dm_timers[id-1];
> - ? ? ? timer->reserved = 1;
> + ? ? ? if (timer) {
> + ? ? ? ? ? ? ? ret = omap_dm_timer_prepare(timer);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 0;
> + ? ? ? ? ? ? ? ? ? ? ? timer = NULL;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> ? ? ? ?spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> - ? ? ? omap_dm_timer_prepare(timer);
> + ? ? ? if (!timer)
> + ? ? ? ? ? ? ? pr_debug("%s: timer%d request failed!\n", __func__, id);
>
> ? ? ? ?return timer;
> ?}
> @@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
> ?void omap_dm_timer_free(struct omap_dm_timer *timer)
> ?{
> - ? ? ? omap_dm_timer_enable(timer);
> - ? ? ? omap_dm_timer_reset(timer);
> ? ? ? ?omap_dm_timer_disable(timer);
> + ? ? ? clk_put(timer->fclk);
>
> ? ? ? ?WARN_ON(!timer->reserved);
> ? ? ? ?timer->reserved = 0;
> @@ -278,15 +202,15 @@ 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;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? if (cpu_class_is_omap2()) {
> + ? ? ? if (!pdata->needs_manual_reset) {
> ? ? ? ? ? ? ? ?clk_enable(timer->fclk);
> ? ? ? ? ? ? ? ?clk_enable(timer->iclk);
> ? ? ? ?}
> -#endif
>
> ? ? ? ?timer->enabled = 1;
> ?}
> @@ -294,15 +218,15 @@ 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;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? if (cpu_class_is_omap2()) {
> + ? ? ? if (!pdata->needs_manual_reset) {
> ? ? ? ? ? ? ? ?clk_disable(timer->iclk);
> ? ? ? ? ? ? ? ?clk_disable(timer->fclk);
> ? ? ? ?}
> -#endif
>
> ? ? ? ?timer->enabled = 0;
> ?}
> @@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
> ?*/
> ?__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
> ?{
> - ? ? ? int i;
> + ? ? ? int i = 0;
> + ? ? ? struct omap_dm_timer *timer = NULL;
> + ? ? ? unsigned long flags;
>
> ? ? ? ?/* If ARMXOR cannot be idled this function call is unnecessary */
> ? ? ? ?if (!(inputmask & (1 << 1)))
> ? ? ? ? ? ? ? ?return inputmask;
>
> ? ? ? ?/* If any active timer is using ARMXOR return modified mask */
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> + ? ? ? spin_lock_irqsave(&dm_timer_lock, flags);
> + ? ? ? list_for_each_entry(timer, &omap_timer_list, node) {
> ? ? ? ? ? ? ? ?u32 l;
>
> - ? ? ? ? ? ? ? l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
> + ? ? ? ? ? ? ? l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ? ? ? ? ?if (l & OMAP_TIMER_CTRL_ST) {
> ? ? ? ? ? ? ? ? ? ? ? ?if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?inputmask &= ~(1 << 1);
> ? ? ? ? ? ? ? ? ? ? ? ?else
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?inputmask &= ~(1 << 2);
> ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? i++;
> ? ? ? ?}
> + ? ? ? spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> ? ? ? ?return inputmask;
> ?}
> @@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
> ?void omap_dm_timer_stop(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?unsigned long rate = 0;
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? rate = clk_get_rate(timer->fclk);
> -#endif
> + ? ? ? if (!pdata->needs_manual_reset)
> + ? ? ? ? ? ? ? rate = clk_get_rate(timer->fclk);
>
> ? ? ? ?__omap_dm_timer_stop(timer, timer->posted, rate);
> ?}
> @@ -395,15 +324,17 @@ 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;
> +
> ? ? ? ?if (source < 0 || source >= 3)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? return __omap_dm_timer_set_source(timer->fclk,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dm_source_clocks[source]);
> -#else
> - ? ? ? return 0;
> -#endif
> + ? ? ? omap_dm_timer_disable(timer);
> + ? ? ? ret = pdata->set_timer_src(timer->pdev, source);
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? return ret;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
>
> @@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
> ?int omap_dm_timers_active(void)
> ?{
> - ? ? ? int i;
> -
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? struct omap_dm_timer *timer;
> -
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> + ? ? ? struct omap_dm_timer *timer;
>
> + ? ? ? list_for_each_entry(timer, &omap_timer_list, node) {
> ? ? ? ? ? ? ? ?if (!timer->enabled)
> ? ? ? ? ? ? ? ? ? ? ? ?continue;
>
> @@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ?timer->id = pdev->id;
> ? ? ? ?timer->irq = irq->start;
> ? ? ? ?timer->pdev = pdev;
> - ? ? ? __omap_dm_timer_init_regs(timer);
>
> ? ? ? ?/* add the timer element to the list */
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> @@ -675,73 +601,3 @@ 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;
> - ? ? ? int i, map_size = SZ_8K; ? ? ? ?/* Module 4KB + L4 4KB except on omap1 */
> -
> - ? ? ? if (!cpu_class_is_omap2())
> - ? ? ? ? ? ? ? return -ENODEV;
> -
> - ? ? ? spin_lock_init(&dm_timer_lock);
> -
> - ? ? ? if (cpu_is_omap24xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap2_dm_timers;
> - ? ? ? ? ? ? ? dm_timer_count = omap2_dm_timer_count;
> - ? ? ? ? ? ? ? dm_source_names = omap2_dm_source_names;
> - ? ? ? ? ? ? ? dm_source_clocks = omap2_dm_source_clocks;
> - ? ? ? } else if (cpu_is_omap34xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap3_dm_timers;
> - ? ? ? ? ? ? ? dm_timer_count = omap3_dm_timer_count;
> - ? ? ? ? ? ? ? dm_source_names = omap3_dm_source_names;
> - ? ? ? ? ? ? ? dm_source_clocks = omap3_dm_source_clocks;
> - ? ? ? } else if (cpu_is_omap44xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap4_dm_timers;
> - ? ? ? ? ? ? ? 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())
> - ? ? ? ? ? ? ? for (i = 0; dm_source_names[i] != NULL; i++)
> - ? ? ? ? ? ? ? ? ? ? ? dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
> -
> - ? ? ? if (cpu_is_omap243x())
> - ? ? ? ? ? ? ? dm_timers[0].phys_base = 0x49018000;
> -
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> -
> - ? ? ? ? ? ? ? /* Static mapping, never released */
> - ? ? ? ? ? ? ? timer->io_base = ioremap(timer->phys_base, map_size);
> - ? ? ? ? ? ? ? BUG_ON(!timer->io_base);
> -
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? ? ? ? ? if (cpu_class_is_omap2()) {
> - ? ? ? ? ? ? ? ? ? ? ? char clk_name[16];
> - ? ? ? ? ? ? ? ? ? ? ? sprintf(clk_name, "gpt%d_ick", i + 1);
> - ? ? ? ? ? ? ? ? ? ? ? timer->iclk = clk_get(NULL, clk_name);
> - ? ? ? ? ? ? ? ? ? ? ? sprintf(clk_name, "gpt%d_fck", i + 1);
> - ? ? ? ? ? ? ? ? ? ? ? timer->fclk = clk_get(NULL, clk_name);
> - ? ? ? ? ? ? ? }
> -
> - ? ? ? ? ? ? ? /* One or two timers may be set up early for sys_timer */
> - ? ? ? ? ? ? ? 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_initcall(omap_dm_timer_init);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 98f186e..2ac7538 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -231,9 +231,8 @@ struct omap_dm_timer {
> ? ? ? ?unsigned long phys_base;
> ? ? ? ?int id;
> ? ? ? ?int irq;
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> ? ? ? ?struct clk *iclk, *fclk;
> -#endif
> +
> ? ? ? ?void __iomem ? ?*io_base;
> ? ? ? ?void __iomem ? ?*sys_stat; ? ? ?/* TISTAT timer status */
> ? ? ? ?void __iomem ? ?*irq_stat; ? ? ?/* TISR/IRQSTATUS interrupt status */
> @@ -251,7 +250,7 @@ struct omap_dm_timer {
> ?};
>
> ?extern u32 sys_timer_reserved;
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer);
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
> ?static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int posted)
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
  2011-09-22  1:00     ` Tony Lindgren
@ 2011-09-22  5:58       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:58 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel, Thara Gopinath

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> 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.
>>
>> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com
>
> I've fixed the missing bracket in the email address     ^^^
Thanks.
--
Tarun
>
> Tony
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
@ 2011-09-22  5:58       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  5:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> 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.
>>
>> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com
>
> I've fixed the missing bracket in the email address ? ? ^^^
Thanks.
--
Tarun
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
  2011-09-22  0:42     ` Tony Lindgren
@ 2011-09-22  6:00       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:00 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

On Thu, Sep 22, 2011 at 6:12 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> The request functions now verify the success of omap_dm_timer_prepare() call
>> after a timer is acquired. If *_prepare() fails then we have to release the
>> timer. In order to avoid race condition during this time, include *_prepare()
>> within lock.
>
> This I've folded into patch 5.
That should be fine.
--
Tarun
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
@ 2011-09-22  6:00       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 22, 2011 at 6:12 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> The request functions now verify the success of omap_dm_timer_prepare() call
>> after a timer is acquired. If *_prepare() fails then we have to release the
>> timer. In order to avoid race condition during this time, include *_prepare()
>> within lock.
>
> This I've folded into patch 5.
That should be fine.
--
Tarun
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
  2011-09-22  1:00     ` Tony Lindgren
@ 2011-09-22  6:05       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:05 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> @@ -514,10 +514,23 @@ 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
>> +
>> +     if (!timer->reserved) {
>> +             pm_runtime_get_sync(&pdev->dev);
>> +             __omap_dm_timer_init_regs(timer);
>> +             timer->tidr = __raw_readl(timer->io_base);
>> +             pm_runtime_put(&pdev->dev);
>>       }
>>
>>       /* add the timer element to the list */
>
> This all should not be necessary. We can pass the reserved flag
> in pdata. Let's replace this one with the patch below.
Yes, this is much better organized.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tony Lindgren <tony@atomide.com>
> Date: Wed, 21 Sep 2011 16:38:51 -0700
> Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers
>
> Pass the reserved flag in pdata and use it. We can
> now make sys_timer_reserved static to mach-omap2/timer.c.
>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index 9c2f588..f1e3ec1 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -69,7 +69,7 @@
>  /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
>  #define MAX_GPTIMER_ID         12
>
> -u32 sys_timer_reserved;
> +static u32 sys_timer_reserved;
>
>  /* Clockevent code */
>
> @@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
>        pdata->set_timer_src = omap2_dm_timer_set_src;
>        pdata->timer_ip_version = oh->class->rev;
>
> +       /* Mark clocksource and clockevent timers as reserved */
> +       if ((sys_timer_reserved >> (id - 1)) & 0x1)
> +               pdata->reserved = 1;
> +
>        od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
>                        omap2_dmtimer_latency,
>                        ARRAY_SIZE(omap2_dmtimer_latency),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index ac904c2..c8df3c3 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>
>        timer->id = pdev->id;
>        timer->irq = irq->start;
> +       timer->reserved = pdata->reserved;
>        timer->pdev = pdev;
>
>        /* Skip pm_runtime_enable for OMAP1 */
> @@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>                pm_runtime_irq_safe(&pdev->dev);
>        }
>
> +       if (!timer->reserved) {
> +               pm_runtime_get_sync(&pdev->dev);
> +               __omap_dm_timer_init_regs(timer);
> +               pm_runtime_put(&pdev->dev);
> +       }
> +
>        /* add the timer element to the list */
>        spin_lock_irqsave(&dm_timer_lock, flags);
>        list_add_tail(&timer->node, &omap_timer_list);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 4e3a326..29764c3 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -77,6 +77,7 @@ struct dmtimer_platform_data {
>        int (*set_timer_src)(struct platform_device *pdev, int source);
>        int timer_ip_version;
>        u32 needs_manual_reset:1;
> +       bool reserved;
>  };
>
>  struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -248,7 +249,6 @@ struct omap_dm_timer {
>        struct list_head node;
>  };
>
> -extern u32 sys_timer_reserved;
>  int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
>  static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
@ 2011-09-22  6:05       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> @@ -514,10 +514,23 @@ 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
>> +
>> + ? ? if (!timer->reserved) {
>> + ? ? ? ? ? ? pm_runtime_get_sync(&pdev->dev);
>> + ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
>> + ? ? ? ? ? ? timer->tidr = __raw_readl(timer->io_base);
>> + ? ? ? ? ? ? pm_runtime_put(&pdev->dev);
>> ? ? ? }
>>
>> ? ? ? /* add the timer element to the list */
>
> This all should not be necessary. We can pass the reserved flag
> in pdata. Let's replace this one with the patch below.
Yes, this is much better organized.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tony Lindgren <tony@atomide.com>
> Date: Wed, 21 Sep 2011 16:38:51 -0700
> Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers
>
> Pass the reserved flag in pdata and use it. We can
> now make sys_timer_reserved static to mach-omap2/timer.c.
>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index 9c2f588..f1e3ec1 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -69,7 +69,7 @@
> ?/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
> ?#define MAX_GPTIMER_ID ? ? ? ? 12
>
> -u32 sys_timer_reserved;
> +static u32 sys_timer_reserved;
>
> ?/* Clockevent code */
>
> @@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
> ? ? ? ?pdata->set_timer_src = omap2_dm_timer_set_src;
> ? ? ? ?pdata->timer_ip_version = oh->class->rev;
>
> + ? ? ? /* Mark clocksource and clockevent timers as reserved */
> + ? ? ? if ((sys_timer_reserved >> (id - 1)) & 0x1)
> + ? ? ? ? ? ? ? pdata->reserved = 1;
> +
> ? ? ? ?od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
> ? ? ? ? ? ? ? ? ? ? ? ?omap2_dmtimer_latency,
> ? ? ? ? ? ? ? ? ? ? ? ?ARRAY_SIZE(omap2_dmtimer_latency),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index ac904c2..c8df3c3 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>
> ? ? ? ?timer->id = pdev->id;
> ? ? ? ?timer->irq = irq->start;
> + ? ? ? timer->reserved = pdata->reserved;
> ? ? ? ?timer->pdev = pdev;
>
> ? ? ? ?/* Skip pm_runtime_enable for OMAP1 */
> @@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?pm_runtime_irq_safe(&pdev->dev);
> ? ? ? ?}
>
> + ? ? ? if (!timer->reserved) {
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&pdev->dev);
> + ? ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
> + ? ? ? ? ? ? ? pm_runtime_put(&pdev->dev);
> + ? ? ? }
> +
> ? ? ? ?/* add the timer element to the list */
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> ? ? ? ?list_add_tail(&timer->node, &omap_timer_list);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 4e3a326..29764c3 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -77,6 +77,7 @@ struct dmtimer_platform_data {
> ? ? ? ?int (*set_timer_src)(struct platform_device *pdev, int source);
> ? ? ? ?int timer_ip_version;
> ? ? ? ?u32 needs_manual_reset:1;
> + ? ? ? bool reserved;
> ?};
>
> ?struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -248,7 +249,6 @@ struct omap_dm_timer {
> ? ? ? ?struct list_head node;
> ?};
>
> -extern u32 sys_timer_reserved;
> ?int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
> ?static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-09-22  1:00     ` Tony Lindgren
@ 2011-09-22  6:07       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:07 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: khilman, linux-omap, linux-arm-kernel

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> 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.
>
> I've updated this to use revision instead of tidr. Updated patch below.
Ok.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:24 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support
>
> 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.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> [tony@atomide.com: updated to use revision instead of tidr]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index f1e3ec1..1140e98 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -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 */
>
> @@ -433,6 +436,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);
>
> @@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
>        if ((sys_timer_reserved >> (id - 1)) & 0x1)
>                pdata->reserved = 1;
>
> +       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),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index c8df3c3..43eb750 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
>        __omap_dm_timer_write(timer, reg, value, timer->posted);
>  }
>
> +static void omap_timer_restore_context(struct omap_dm_timer *timer)
> +{
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
> +                               timer->context.tiocp_cfg);
> +       if (timer->revision > 1)
> +               __raw_writel(timer->context.tistat, timer->sys_stat);
> +
> +       __raw_writel(timer->context.tisr, timer->irq_stat);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
> +                               timer->context.twer);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
> +                               timer->context.tcrr);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
> +                               timer->context.tldr);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
> +                               timer->context.tmar);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
> +                               timer->context.tsicr);
> +       __raw_writel(timer->context.tier, timer->irq_ena);
> +       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
> +                               timer->context.tclr);
> +}
> +
>  static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>  {
>        int c;
> @@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
>  static void omap_dm_timer_reset(struct omap_dm_timer *timer)
>  {
> +       omap_dm_timer_enable(timer);
>        if (timer->pdev->id != 1) {
>                omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
>                omap_dm_timer_wait_for_reset(timer);
>        }
>
>        __omap_dm_timer_reset(timer, 0, 0);
> +       omap_dm_timer_disable(timer);
>        timer->posted = 1;
>  }
>
> @@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
>                return -EINVAL;
>        }
>
> -       omap_dm_timer_enable(timer);
> -
>        if (pdata->needs_manual_reset)
>                omap_dm_timer_reset(timer);
>
> @@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
>  void omap_dm_timer_free(struct omap_dm_timer *timer)
>  {
> -       omap_dm_timer_disable(timer);
>        clk_put(timer->fclk);
>
>        WARN_ON(!timer->reserved);
> @@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
>
>  void 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;
> +       }
> +
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
> @@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
> +
> +       if (timer->loses_context) {
> +               u32 ctx_loss_cnt_after =
> +                       timer->get_context_loss_count(&timer->pdev->dev);
> +               if (ctx_loss_cnt_after != timer->ctx_loss_count)
> +                       omap_timer_restore_context(timer);
> +       }
> +
>        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>        if (!(l & OMAP_TIMER_CTRL_ST)) {
>                l |= OMAP_TIMER_CTRL_ST;
>                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
>        }
> +
> +       /* Save the context */
> +       timer->context.tclr = l;
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_start);
>
> @@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
>        if (source < 0 || source >= 3)
>                return -EINVAL;
>
> -       omap_dm_timer_disable(timer);
>        ret = pdata->set_timer_src(timer->pdev, source);
> -       omap_dm_timer_enable(timer);
>
>        return ret;
>  }
> @@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
>        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>        if (autoreload)
>                l |= OMAP_TIMER_CTRL_AR;
> @@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
>
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
> +       /* Save the context */
> +       timer->context.tclr = l;
> +       timer->context.tldr = load;
> +       omap_dm_timer_disable(timer);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
>
> @@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
> +
> +       if (timer->loses_context) {
> +               u32 ctx_loss_cnt_after =
> +                       timer->get_context_loss_count(&timer->pdev->dev);
> +               if (ctx_loss_cnt_after != timer->ctx_loss_count)
> +                       omap_timer_restore_context(timer);
> +       }
> +
>        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>        if (autoreload) {
>                l |= OMAP_TIMER_CTRL_AR;
> @@ -352,6 +403,11 @@ 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, l, load, timer->posted);
> +
> +       /* Save the context */
> +       timer->context.tclr = l;
> +       timer->context.tldr = load;
> +       timer->context.tcrr = load;
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
>
> @@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
>        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>        if (enable)
>                l |= OMAP_TIMER_CTRL_CE;
> @@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
>                l &= ~OMAP_TIMER_CTRL_CE;
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
> +
> +       /* Save the context */
> +       timer->context.tclr = l;
> +       timer->context.tmar = match;
> +       omap_dm_timer_disable(timer);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
>
> @@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
>        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));
> @@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
>                l |= OMAP_TIMER_CTRL_PT;
>        l |= trigger << 10;
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> +       /* Save the context */
> +       timer->context.tclr = l;
> +       omap_dm_timer_disable(timer);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
>
> @@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
>  {
>        u32 l;
>
> +       omap_dm_timer_enable(timer);
>        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>        l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
>        if (prescaler >= 0x00 && prescaler <= 0x07) {
> @@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
>                l |= prescaler << 2;
>        }
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> +       /* Save the context */
> +       timer->context.tclr = l;
> +       omap_dm_timer_disable(timer);
>  }
>  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_enable(timer);
>        __omap_dm_timer_int_enable(timer, value);
> +
> +       /* Save the context */
> +       timer->context.tier = value;
> +       timer->context.twer = value;
> +       omap_dm_timer_disable(timer);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
>
> @@ -412,6 +490,11 @@ 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);
> +               return 0;
> +       }
> +
>        l = __raw_readl(timer->irq_stat);
>
>        return l;
> @@ -421,18 +504,33 @@ 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, value);
> +       /* Save the context */
> +       timer->context.tisr = value;
>  }
>  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);
> +               return 0;
> +       }
> +
>        return __omap_dm_timer_read_counter(timer, timer->posted);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
>
>  void 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;
> +       }
> +
>        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
> +
> +       /* Save the context */
> +       timer->context.tcrr = value;
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
> @@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>        timer->irq = irq->start;
>        timer->reserved = pdata->reserved;
>        timer->pdev = pdev;
> +       timer->loses_context = pdata->loses_context;
> +       timer->get_context_loss_count = pdata->get_context_loss_count;
>
>        /* Skip pm_runtime_enable for OMAP1 */
>        if (!pdata->needs_manual_reset) {
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 29764c3..9519d87 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
>  struct omap_dm_timer;
>  struct clk;
>
> +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 dmtimer_platform_data {
>        int (*set_timer_src)(struct platform_device *pdev, int source);
>        int timer_ip_version;
>        u32 needs_manual_reset:1;
>        bool reserved;
> +
> +       bool loses_context;
> +
> +       u32 (*get_context_loss_count)(struct device *dev);
>  };
>
>  struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -245,8 +272,14 @@ struct omap_dm_timer {
>        unsigned long rate;
>        unsigned reserved:1;
>        unsigned posted:1;
> +       struct timer_regs context;
> +       bool loses_context;
> +       int ctx_loss_count;
> +       int revision;
>        struct platform_device *pdev;
>        struct list_head node;
> +
> +       u32 (*get_context_loss_count)(struct device *dev);
>  };
>
>  int omap_dm_timer_prepare(struct omap_dm_timer *timer);
> @@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
>        /* Assume v1 ip if bits [31:16] are zero */
>        tidr = __raw_readl(timer->io_base);
>        if (!(tidr >> 16)) {
> +               timer->revision = 1;
>                timer->sys_stat = timer->io_base +
>                                OMAP_TIMER_V1_SYS_STAT_OFFSET;
>                timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
> @@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
>                timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
>                timer->func_base = timer->io_base;
>        } else {
> +               timer->revision = 2;
>                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;
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-09-22  6:07       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> 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.
>
> I've updated this to use revision instead of tidr. Updated patch below.
Ok.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:24 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support
>
> 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.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> [tony at atomide.com: updated to use revision instead of tidr]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index f1e3ec1..1140e98 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -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 */
>
> @@ -433,6 +436,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);
>
> @@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
> ? ? ? ?if ((sys_timer_reserved >> (id - 1)) & 0x1)
> ? ? ? ? ? ? ? ?pdata->reserved = 1;
>
> + ? ? ? 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),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index c8df3c3..43eb750 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ?__omap_dm_timer_write(timer, reg, value, timer->posted);
> ?}
>
> +static void omap_timer_restore_context(struct omap_dm_timer *timer)
> +{
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tiocp_cfg);
> + ? ? ? if (timer->revision > 1)
> + ? ? ? ? ? ? ? __raw_writel(timer->context.tistat, timer->sys_stat);
> +
> + ? ? ? __raw_writel(timer->context.tisr, timer->irq_stat);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.twer);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tcrr);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tldr);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tmar);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tsicr);
> + ? ? ? __raw_writel(timer->context.tier, timer->irq_ena);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tclr);
> +}
> +
> ?static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?int c;
> @@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
> ?static void omap_dm_timer_reset(struct omap_dm_timer *timer)
> ?{
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?if (timer->pdev->id != 1) {
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
> ? ? ? ? ? ? ? ?omap_dm_timer_wait_for_reset(timer);
> ? ? ? ?}
>
> ? ? ? ?__omap_dm_timer_reset(timer, 0, 0);
> + ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?timer->posted = 1;
> ?}
>
> @@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
>
> - ? ? ? omap_dm_timer_enable(timer);
> -
> ? ? ? ?if (pdata->needs_manual_reset)
> ? ? ? ? ? ? ? ?omap_dm_timer_reset(timer);
>
> @@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
> ?void omap_dm_timer_free(struct omap_dm_timer *timer)
> ?{
> - ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?clk_put(timer->fclk);
>
> ? ? ? ?WARN_ON(!timer->reserved);
> @@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
>
> ?void 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;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
> @@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? if (timer->loses_context) {
> + ? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
> + ? ? ? ? ? ? ? if (ctx_loss_cnt_after != timer->ctx_loss_count)
> + ? ? ? ? ? ? ? ? ? ? ? omap_timer_restore_context(timer);
> + ? ? ? }
> +
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (!(l & OMAP_TIMER_CTRL_ST)) {
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_ST;
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> ? ? ? ?}
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_start);
>
> @@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
> ? ? ? ?if (source < 0 || source >= 3)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> - ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?ret = pdata->set_timer_src(timer->pdev, source);
> - ? ? ? omap_dm_timer_enable(timer);
>
> ? ? ? ?return ret;
> ?}
> @@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (autoreload)
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_AR;
> @@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
>
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tldr = load;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
>
> @@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? if (timer->loses_context) {
> + ? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
> + ? ? ? ? ? ? ? if (ctx_loss_cnt_after != timer->ctx_loss_count)
> + ? ? ? ? ? ? ? ? ? ? ? omap_timer_restore_context(timer);
> + ? ? ? }
> +
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (autoreload) {
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_AR;
> @@ -352,6 +403,11 @@ 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, l, load, timer->posted);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tldr = load;
> + ? ? ? timer->context.tcrr = load;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
>
> @@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (enable)
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_CE;
> @@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
> ? ? ? ? ? ? ? ?l &= ~OMAP_TIMER_CTRL_CE;
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tmar = match;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
>
> @@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?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));
> @@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_PT;
> ? ? ? ?l |= trigger << 10;
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
>
> @@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
> ? ? ? ?if (prescaler >= 0x00 && prescaler <= 0x07) {
> @@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
> ? ? ? ? ? ? ? ?l |= prescaler << 2;
> ? ? ? ?}
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?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_enable(timer);
> ? ? ? ?__omap_dm_timer_int_enable(timer, value);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tier = value;
> + ? ? ? timer->context.twer = value;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
>
> @@ -412,6 +490,11 @@ 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);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> +
> ? ? ? ?l = __raw_readl(timer->irq_stat);
>
> ? ? ? ?return l;
> @@ -421,18 +504,33 @@ 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, value);
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tisr = value;
> ?}
> ?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);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> +
> ? ? ? ?return __omap_dm_timer_read_counter(timer, timer->posted);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
>
> ?void 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;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tcrr = value;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
> @@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ?timer->irq = irq->start;
> ? ? ? ?timer->reserved = pdata->reserved;
> ? ? ? ?timer->pdev = pdev;
> + ? ? ? timer->loses_context = pdata->loses_context;
> + ? ? ? timer->get_context_loss_count = pdata->get_context_loss_count;
>
> ? ? ? ?/* Skip pm_runtime_enable for OMAP1 */
> ? ? ? ?if (!pdata->needs_manual_reset) {
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 29764c3..9519d87 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
> ?struct omap_dm_timer;
> ?struct clk;
>
> +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 dmtimer_platform_data {
> ? ? ? ?int (*set_timer_src)(struct platform_device *pdev, int source);
> ? ? ? ?int timer_ip_version;
> ? ? ? ?u32 needs_manual_reset:1;
> ? ? ? ?bool reserved;
> +
> + ? ? ? bool loses_context;
> +
> + ? ? ? u32 (*get_context_loss_count)(struct device *dev);
> ?};
>
> ?struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -245,8 +272,14 @@ struct omap_dm_timer {
> ? ? ? ?unsigned long rate;
> ? ? ? ?unsigned reserved:1;
> ? ? ? ?unsigned posted:1;
> + ? ? ? struct timer_regs context;
> + ? ? ? bool loses_context;
> + ? ? ? int ctx_loss_count;
> + ? ? ? int revision;
> ? ? ? ?struct platform_device *pdev;
> ? ? ? ?struct list_head node;
> +
> + ? ? ? u32 (*get_context_loss_count)(struct device *dev);
> ?};
>
> ?int omap_dm_timer_prepare(struct omap_dm_timer *timer);
> @@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
> ? ? ? ?/* Assume v1 ip if bits [31:16] are zero */
> ? ? ? ?tidr = __raw_readl(timer->io_base);
> ? ? ? ?if (!(tidr >> 16)) {
> + ? ? ? ? ? ? ? timer->revision = 1;
> ? ? ? ? ? ? ? ?timer->sys_stat = timer->io_base +
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_V1_SYS_STAT_OFFSET;
> ? ? ? ? ? ? ? ?timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
> @@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
> ? ? ? ? ? ? ? ?timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
> ? ? ? ? ? ? ? ?timer->func_base = timer->io_base;
> ? ? ? ?} else {
> + ? ? ? ? ? ? ? timer->revision = 2;
> ? ? ? ? ? ? ? ?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;
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-22  0:59   ` Tony Lindgren
@ 2011-09-22  6:09     ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:09 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

On Thu, Sep 22, 2011 at 6:29 AM, Tony Lindgren <tony@atomide.com> wrote:
> Hi Tarun,
>
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> Adaptation of dmtimer code to platform driver using omap_device and
>> omap_hwmod abstraction. It also include pm-runtime and off-mode support.
>
> I've applied these into dmtimer branch with some changes to simplify
> things further. I've also merged it into linux-omap master branch
> for further testing.
>
> I'll reply to your patches with the changes I've done. Care give the
> dmtimer branch a try and see if I've missed something?
Sure, I will go through the changes and do testing on it.
--
Tarun
>
> Regards,
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-22  6:09     ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-22  6:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 22, 2011 at 6:29 AM, Tony Lindgren <tony@atomide.com> wrote:
> Hi Tarun,
>
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> Adaptation of dmtimer code to platform driver using omap_device and
>> omap_hwmod abstraction. It also include pm-runtime and off-mode support.
>
> I've applied these into dmtimer branch with some changes to simplify
> things further. I've also merged it into linux-omap master branch
> for further testing.
>
> I'll reply to your patches with the changes I've done. Care give the
> dmtimer branch a try and see if I've missed something?
Sure, I will go through the changes and do testing on it.
--
Tarun
>
> Regards,
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-22  6:09     ` DebBarma, Tarun Kanti
@ 2011-09-23  9:27       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-23  9:27 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

Hi Tony,
[...]
>> I've applied these into dmtimer branch with some changes to simplify
>> things further. I've also merged it into linux-omap master branch
>> for further testing.
>>
>> I'll reply to your patches with the changes I've done. Care give the
>> dmtimer branch a try and see if I've missed something?
> Sure, I will go through the changes and do testing on it.
Please find the missing/correction in the patch below.
You can include them as part of patch 9.
Thanks.
--
Tarun

>From 98cb7949054214684d7361eed2e382fa716ab0da Mon Sep 17 00:00:00 2001
From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
Date: Fri, 23 Sep 2011 14:48:56 +0530
Subject: [correction] [PATCH 09/12] OMAP: dmtimer: low-power mode support

These are some missing content as well as correction to this patch.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
---
 arch/arm/plat-omap/dmtimer.c |   21 ++++++++++++++++++---
 1 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index de7896f..81a2305 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -79,9 +79,9 @@ static void omap_dm_timer_write_reg(struct
omap_dm_timer *timer, u32 reg,

 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
-				timer->context.tiocp_cfg);
-	if (timer->revision > 1)
+	__raw_writel(timer->context.tiocp_cfg,
+			timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
+	if (timer->revision == 1)
 		__raw_writel(timer->context.tistat, timer->sys_stat);

 	__raw_writel(timer->context.tisr, timer->irq_stat);
@@ -356,6 +356,21 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)

 	__omap_dm_timer_stop(timer, timer->posted, rate);

+	if (timer->loses_context) {
+		if (timer->get_context_loss_count)
+			timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+	}
+
+	/*
+	 * Since the register values are computed and written within
+	 * __omap_dm_timer_stop, we need to use read to retrieve the
+	 * context.
+	 */
+	timer->context.tclr =
+			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+	timer->context.tisr = __raw_readl(timer->irq_stat);
+	omap_dm_timer_disable(timer);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-23  9:27       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-23  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tony,
[...]
>> I've applied these into dmtimer branch with some changes to simplify
>> things further. I've also merged it into linux-omap master branch
>> for further testing.
>>
>> I'll reply to your patches with the changes I've done. Care give the
>> dmtimer branch a try and see if I've missed something?
> Sure, I will go through the changes and do testing on it.
Please find the missing/correction in the patch below.
You can include them as part of patch 9.
Thanks.
--
Tarun

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-23  9:27       ` DebBarma, Tarun Kanti
@ 2011-09-26 17:25         ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-26 17:25 UTC (permalink / raw)
  To: DebBarma, Tarun Kanti; +Cc: linux-omap, khilman, linux-arm-kernel

* DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110923 01:54]:
> Hi Tony,
> [...]
> >> I've applied these into dmtimer branch with some changes to simplify
> >> things further. I've also merged it into linux-omap master branch
> >> for further testing.
> >>
> >> I'll reply to your patches with the changes I've done. Care give the
> >> dmtimer branch a try and see if I've missed something?
> > Sure, I will go through the changes and do testing on it.
> Please find the missing/correction in the patch below.
> You can include them as part of patch 9.

Thanks I've updated your original patch with that. The missing part
I probably accidentally dropped while rebasing, sorry about that.

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-26 17:25         ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-09-26 17:25 UTC (permalink / raw)
  To: linux-arm-kernel

* DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110923 01:54]:
> Hi Tony,
> [...]
> >> I've applied these into dmtimer branch with some changes to simplify
> >> things further. I've also merged it into linux-omap master branch
> >> for further testing.
> >>
> >> I'll reply to your patches with the changes I've done. Care give the
> >> dmtimer branch a try and see if I've missed something?
> > Sure, I will go through the changes and do testing on it.
> Please find the missing/correction in the patch below.
> You can include them as part of patch 9.

Thanks I've updated your original patch with that. The missing part
I probably accidentally dropped while rebasing, sorry about that.

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-26 17:25         ` Tony Lindgren
@ 2011-09-26 18:38           ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-26 18:38 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap, khilman, linux-arm-kernel

On Mon, Sep 26, 2011 at 10:55 PM, Tony Lindgren <tony@atomide.com> wrote:
> * DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110923 01:54]:
>> Hi Tony,
>> [...]
>> >> I've applied these into dmtimer branch with some changes to simplify
>> >> things further. I've also merged it into linux-omap master branch
>> >> for further testing.
>> >>
>> >> I'll reply to your patches with the changes I've done. Care give the
>> >> dmtimer branch a try and see if I've missed something?
>> > Sure, I will go through the changes and do testing on it.
>> Please find the missing/correction in the patch below.
>> You can include them as part of patch 9.
>
> Thanks I've updated your original patch with that. The missing part
> I probably accidentally dropped while rebasing, sorry about that.
Ok, no problem.
--
Tarun
>
> Regards,
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-09-26 18:38           ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-09-26 18:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Sep 26, 2011 at 10:55 PM, Tony Lindgren <tony@atomide.com> wrote:
> * DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110923 01:54]:
>> Hi Tony,
>> [...]
>> >> I've applied these into dmtimer branch with some changes to simplify
>> >> things further. I've also merged it into linux-omap master branch
>> >> for further testing.
>> >>
>> >> I'll reply to your patches with the changes I've done. Care give the
>> >> dmtimer branch a try and see if I've missed something?
>> > Sure, I will go through the changes and do testing on it.
>> Please find the missing/correction in the patch below.
>> You can include them as part of patch 9.
>
> Thanks I've updated your original patch with that. The missing part
> I probably accidentally dropped while rebasing, sorry about that.
Ok, no problem.
--
Tarun
>
> Regards,
>
> Tony
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-09-20 11:30 ` Tarun Kanti DebBarma
@ 2011-10-03 14:33   ` Cousson, Benoit
  -1 siblings, 0 replies; 76+ messages in thread
From: Cousson, Benoit @ 2011-10-03 14:33 UTC (permalink / raw)
  To: DebBarma, Tarun Kanti, tony
  Cc: linux-omap, Hilman, Kevin, linux-arm-kernel, arnd Bergmann

+ Arnd

Hi Tony,

After rebasing by DT series on top of your dt-base, I noticed two minor 
issues from this timer series.

First some new warnings:

[    0.260009]  omap_timer.1: alias fck already exists
[    0.260345]  omap_timer.2: alias fck already exists
[    0.260650]  omap_timer.3: alias fck already exists
[    0.260955]  omap_timer.4: alias fck already exists
[    0.261260]  omap_timer.5: alias fck already exists
[    0.261566]  omap_timer.6: alias fck already exists
[    0.261871]  omap_timer.7: alias fck already exists
[    0.262207]  omap_timer.8: alias fck already exists
[    0.262512]  omap_timer.9: alias fck already exists
[    0.262847]  omap_timer.10: alias fck already exists
[    0.263153]  omap_timer.11: alias fck already exists

These warnings are due to the commit 
318c3e15cd55c73a26ae22a65a8183655b3003f9  ARM: OMAP2+: dmtimer: add 
device names to flck nodes

Since 3.1, the fck clock nodes are added automatically based on hwmod 
main_clk attribute.

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

So they should not exist in this patch.

Moreover, all the legacy clockdev should be removed at the same time.

CLK(NULL,	"gpt1_fck",		&timer1_fck,	CK_443X),
CLK(NULL,	"gpt10_fck",		&timer10_fck,	CK_443X),
CLK(NULL,	"gpt11_fck",		&timer11_fck,	CK_443X),
CLK(NULL,	"gpt2_fck",		&timer2_fck,	CK_443X),
CLK(NULL,	"gpt3_fck",		&timer3_fck,	CK_443X),
CLK(NULL,	"gpt4_fck",		&timer4_fck,	CK_443X),
CLK(NULL,	"gpt5_fck",		&timer5_fck,	CK_443X),
CLK(NULL,	"gpt6_fck",		&timer6_fck,	CK_443X),
CLK(NULL,	"gpt7_fck",		&timer7_fck,	CK_443X),
CLK(NULL,	"gpt8_fck",		&timer8_fck,	CK_443X),
CLK(NULL,	"gpt9_fck",		&timer9_fck,	CK_443X),
CLK(NULL,	"gpt1_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt2_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt3_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt4_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt5_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt6_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt7_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt8_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt9_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt10_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt11_ick",		&dummy_ck,	CK_443X),

That will reduce a little bit the size of these static data files.



Secondly, in commit c345c8b09d7a131f3571af55341038054a79efbd ARM: 
OMAP2+: dmtimer: convert to platform devices

+struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+       {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+

That structure should be removed, since I added a default one in the 
omap_device cleanup series for 3.2. Assuming that the cleanup is pulled 
before the new feature, the timer series could avoid adding that.

How do you want to handle that, using some cleanup patch on top of your 
current branch or by resubmitting the series?
The point is that this branch was already pulled by Arnd in 
arm-soc/next/dmtimer feature branch.

Regards,
Benoit

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-10-03 14:33   ` Cousson, Benoit
  0 siblings, 0 replies; 76+ messages in thread
From: Cousson, Benoit @ 2011-10-03 14:33 UTC (permalink / raw)
  To: linux-arm-kernel

+ Arnd

Hi Tony,

After rebasing by DT series on top of your dt-base, I noticed two minor 
issues from this timer series.

First some new warnings:

[    0.260009]  omap_timer.1: alias fck already exists
[    0.260345]  omap_timer.2: alias fck already exists
[    0.260650]  omap_timer.3: alias fck already exists
[    0.260955]  omap_timer.4: alias fck already exists
[    0.261260]  omap_timer.5: alias fck already exists
[    0.261566]  omap_timer.6: alias fck already exists
[    0.261871]  omap_timer.7: alias fck already exists
[    0.262207]  omap_timer.8: alias fck already exists
[    0.262512]  omap_timer.9: alias fck already exists
[    0.262847]  omap_timer.10: alias fck already exists
[    0.263153]  omap_timer.11: alias fck already exists

These warnings are due to the commit 
318c3e15cd55c73a26ae22a65a8183655b3003f9  ARM: OMAP2+: dmtimer: add 
device names to flck nodes

Since 3.1, the fck clock nodes are added automatically based on hwmod 
main_clk attribute.

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

So they should not exist in this patch.

Moreover, all the legacy clockdev should be removed at the same time.

CLK(NULL,	"gpt1_fck",		&timer1_fck,	CK_443X),
CLK(NULL,	"gpt10_fck",		&timer10_fck,	CK_443X),
CLK(NULL,	"gpt11_fck",		&timer11_fck,	CK_443X),
CLK(NULL,	"gpt2_fck",		&timer2_fck,	CK_443X),
CLK(NULL,	"gpt3_fck",		&timer3_fck,	CK_443X),
CLK(NULL,	"gpt4_fck",		&timer4_fck,	CK_443X),
CLK(NULL,	"gpt5_fck",		&timer5_fck,	CK_443X),
CLK(NULL,	"gpt6_fck",		&timer6_fck,	CK_443X),
CLK(NULL,	"gpt7_fck",		&timer7_fck,	CK_443X),
CLK(NULL,	"gpt8_fck",		&timer8_fck,	CK_443X),
CLK(NULL,	"gpt9_fck",		&timer9_fck,	CK_443X),
CLK(NULL,	"gpt1_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt2_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt3_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt4_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt5_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt6_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt7_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt8_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt9_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt10_ick",		&dummy_ck,	CK_443X),
CLK(NULL,	"gpt11_ick",		&dummy_ck,	CK_443X),

That will reduce a little bit the size of these static data files.



Secondly, in commit c345c8b09d7a131f3571af55341038054a79efbd ARM: 
OMAP2+: dmtimer: convert to platform devices

+struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+       {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+

That structure should be removed, since I added a default one in the 
omap_device cleanup series for 3.2. Assuming that the cleanup is pulled 
before the new feature, the timer series could avoid adding that.

How do you want to handle that, using some cleanup patch on top of your 
current branch or by resubmitting the series?
The point is that this branch was already pulled by Arnd in 
arm-soc/next/dmtimer feature branch.

Regards,
Benoit

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
  2011-10-03 14:33   ` Cousson, Benoit
@ 2011-10-04  0:36     ` Tony Lindgren
  -1 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-10-04  0:36 UTC (permalink / raw)
  To: Cousson, Benoit
  Cc: DebBarma, Tarun Kanti, linux-omap, Hilman, Kevin,
	linux-arm-kernel, arnd Bergmann

* Cousson, Benoit <b-cousson@ti.com> [111003 07:00]:
> + Arnd
> 
> Hi Tony,
> 
> After rebasing by DT series on top of your dt-base, I noticed two
> minor issues from this timer series.
> 
> First some new warnings:
> 
> [    0.260009]  omap_timer.1: alias fck already exists
> [    0.260345]  omap_timer.2: alias fck already exists
> [    0.260650]  omap_timer.3: alias fck already exists
> [    0.260955]  omap_timer.4: alias fck already exists
> [    0.261260]  omap_timer.5: alias fck already exists
> [    0.261566]  omap_timer.6: alias fck already exists
> [    0.261871]  omap_timer.7: alias fck already exists
> [    0.262207]  omap_timer.8: alias fck already exists
> [    0.262512]  omap_timer.9: alias fck already exists
> [    0.262847]  omap_timer.10: alias fck already exists
> [    0.263153]  omap_timer.11: alias fck already exists
> 
> These warnings are due to the commit
> 318c3e15cd55c73a26ae22a65a8183655b3003f9  ARM: OMAP2+: dmtimer: add
> device names to flck nodes

Yes I noticed those too, but too late :(
 
> Since 3.1, the fck clock nodes are added automatically based on
> hwmod main_clk attribute.
> 
> +       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),
> 
> So they should not exist in this patch.
> 
> Moreover, all the legacy clockdev should be removed at the same time.
> 
> CLK(NULL,	"gpt1_fck",		&timer1_fck,	CK_443X),
> CLK(NULL,	"gpt10_fck",		&timer10_fck,	CK_443X),
> CLK(NULL,	"gpt11_fck",		&timer11_fck,	CK_443X),
> CLK(NULL,	"gpt2_fck",		&timer2_fck,	CK_443X),
> CLK(NULL,	"gpt3_fck",		&timer3_fck,	CK_443X),
> CLK(NULL,	"gpt4_fck",		&timer4_fck,	CK_443X),
> CLK(NULL,	"gpt5_fck",		&timer5_fck,	CK_443X),
> CLK(NULL,	"gpt6_fck",		&timer6_fck,	CK_443X),
> CLK(NULL,	"gpt7_fck",		&timer7_fck,	CK_443X),
> CLK(NULL,	"gpt8_fck",		&timer8_fck,	CK_443X),
> CLK(NULL,	"gpt9_fck",		&timer9_fck,	CK_443X),
> CLK(NULL,	"gpt1_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt2_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt3_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt4_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt5_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt6_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt7_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt8_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt9_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt10_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt11_ick",		&dummy_ck,	CK_443X),
> 
> That will reduce a little bit the size of these static data files.
 
OK 
 
> Secondly, in commit c345c8b09d7a131f3571af55341038054a79efbd ARM:
> OMAP2+: dmtimer: convert to platform devices
> 
> +struct omap_device_pm_latency omap2_dmtimer_latency[] = {
> +       {
> +               .deactivate_func = omap_device_idle_hwmods,
> +               .activate_func   = omap_device_enable_hwmods,
> +               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
> +       },
> +};
> +
> 
> That structure should be removed, since I added a default one in the
> omap_device cleanup series for 3.2. Assuming that the cleanup is
> pulled before the new feature, the timer series could avoid adding
> that.

OK
 
> How do you want to handle that, using some cleanup patch on top of
> your current branch or by resubmitting the series?
> The point is that this branch was already pulled by Arnd in
> arm-soc/next/dmtimer feature branch.

Can you please just do a fix on either the dmtimer branch or
on cleanup branch?

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
@ 2011-10-04  0:36     ` Tony Lindgren
  0 siblings, 0 replies; 76+ messages in thread
From: Tony Lindgren @ 2011-10-04  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

* Cousson, Benoit <b-cousson@ti.com> [111003 07:00]:
> + Arnd
> 
> Hi Tony,
> 
> After rebasing by DT series on top of your dt-base, I noticed two
> minor issues from this timer series.
> 
> First some new warnings:
> 
> [    0.260009]  omap_timer.1: alias fck already exists
> [    0.260345]  omap_timer.2: alias fck already exists
> [    0.260650]  omap_timer.3: alias fck already exists
> [    0.260955]  omap_timer.4: alias fck already exists
> [    0.261260]  omap_timer.5: alias fck already exists
> [    0.261566]  omap_timer.6: alias fck already exists
> [    0.261871]  omap_timer.7: alias fck already exists
> [    0.262207]  omap_timer.8: alias fck already exists
> [    0.262512]  omap_timer.9: alias fck already exists
> [    0.262847]  omap_timer.10: alias fck already exists
> [    0.263153]  omap_timer.11: alias fck already exists
> 
> These warnings are due to the commit
> 318c3e15cd55c73a26ae22a65a8183655b3003f9  ARM: OMAP2+: dmtimer: add
> device names to flck nodes

Yes I noticed those too, but too late :(
 
> Since 3.1, the fck clock nodes are added automatically based on
> hwmod main_clk attribute.
> 
> +       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),
> 
> So they should not exist in this patch.
> 
> Moreover, all the legacy clockdev should be removed at the same time.
> 
> CLK(NULL,	"gpt1_fck",		&timer1_fck,	CK_443X),
> CLK(NULL,	"gpt10_fck",		&timer10_fck,	CK_443X),
> CLK(NULL,	"gpt11_fck",		&timer11_fck,	CK_443X),
> CLK(NULL,	"gpt2_fck",		&timer2_fck,	CK_443X),
> CLK(NULL,	"gpt3_fck",		&timer3_fck,	CK_443X),
> CLK(NULL,	"gpt4_fck",		&timer4_fck,	CK_443X),
> CLK(NULL,	"gpt5_fck",		&timer5_fck,	CK_443X),
> CLK(NULL,	"gpt6_fck",		&timer6_fck,	CK_443X),
> CLK(NULL,	"gpt7_fck",		&timer7_fck,	CK_443X),
> CLK(NULL,	"gpt8_fck",		&timer8_fck,	CK_443X),
> CLK(NULL,	"gpt9_fck",		&timer9_fck,	CK_443X),
> CLK(NULL,	"gpt1_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt2_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt3_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt4_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt5_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt6_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt7_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt8_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt9_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt10_ick",		&dummy_ck,	CK_443X),
> CLK(NULL,	"gpt11_ick",		&dummy_ck,	CK_443X),
> 
> That will reduce a little bit the size of these static data files.
 
OK 
 
> Secondly, in commit c345c8b09d7a131f3571af55341038054a79efbd ARM:
> OMAP2+: dmtimer: convert to platform devices
> 
> +struct omap_device_pm_latency omap2_dmtimer_latency[] = {
> +       {
> +               .deactivate_func = omap_device_idle_hwmods,
> +               .activate_func   = omap_device_enable_hwmods,
> +               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
> +       },
> +};
> +
> 
> That structure should be removed, since I added a default one in the
> omap_device cleanup series for 3.2. Assuming that the cleanup is
> pulled before the new feature, the timer series could avoid adding
> that.

OK
 
> How do you want to handle that, using some cleanup patch on top of
> your current branch or by resubmitting the series?
> The point is that this branch was already pulled by Arnd in
> arm-soc/next/dmtimer feature branch.

Can you please just do a fix on either the dmtimer branch or
on cleanup branch?

Regards,

Tony

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-09-20 11:30   ` Tarun Kanti DebBarma
@ 2011-11-15 17:57     ` Omar Ramirez Luna
  -1 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-15 17:57 UTC (permalink / raw)
  To: Tarun Kanti DebBarma
  Cc: linux-omap, khilman, tony, linux-arm-kernel, Santosh Shilimkar

Hi Tarun,

On Tue, Sep 20, 2011 at 6:30 AM, Tarun Kanti DebBarma
<tarun.kanti@ti.com> wrote:
> 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.

Now that handling of the clock has been decoupled from
omap_dm_timer_request_specific/free and placed in start/stop
functions, there is a "possible irq lock inversion dependency
detected" for any attempt to enable the clock from soft|hard irq.

My use case is as follows:

DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
for processing the message, when it reaches tidspbridge it turns out
that the DSP wants to enable a gpt timer; however, locks involved
"clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
have been called from unsafe contexts in the past
(http://pastebin.com/7Dtz8t0f).

Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?

...
> @@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
>                rate = clk_get_rate(timer->fclk);
>
>        __omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
> +
> +       if (timer->loses_context) {
> +               if (timer->get_context_loss_count)
> +                       timer->ctx_loss_count =
> +                       timer->get_context_loss_count(&timer->pdev->dev);
> +       }
> +
> +       /*
> +        * Since the register values are computed and written within
> +        * __omap_dm_timer_stop, we need to use read to retrieve the
> +        * context.
> +        */
> +       timer->context.tclr =
> +                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> +       timer->context.tisr = __raw_readl(timer->irq_stat);
> +       omap_dm_timer_disable(timer);
>  }
>  EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>

I didn't review the whole patch, but at least this part is not in
mainline, it seems like the patch modified by Tony and the v16 were
not the same.

I could diff and include the missing parts, if someone can confirm
that we need v16, which I believe so, since current stop function
doesn't call omap_dm_timer_disable.

Regards,

Omar
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-11-15 17:57     ` Omar Ramirez Luna
  0 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-15 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tarun,

On Tue, Sep 20, 2011 at 6:30 AM, Tarun Kanti DebBarma
<tarun.kanti@ti.com> wrote:
> 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.

Now that handling of the clock has been decoupled from
omap_dm_timer_request_specific/free and placed in start/stop
functions, there is a "possible irq lock inversion dependency
detected" for any attempt to enable the clock from soft|hard irq.

My use case is as follows:

DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
for processing the message, when it reaches tidspbridge it turns out
that the DSP wants to enable a gpt timer; however, locks involved
"clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
have been called from unsafe contexts in the past
(http://pastebin.com/7Dtz8t0f).

Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?

...
> @@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
> ? ? ? ? ? ? ? ?rate = clk_get_rate(timer->fclk);
>
> ? ? ? ?__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
> +
> + ? ? ? if (timer->loses_context) {
> + ? ? ? ? ? ? ? if (timer->get_context_loss_count)
> + ? ? ? ? ? ? ? ? ? ? ? timer->ctx_loss_count =
> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
> + ? ? ? }
> +
> + ? ? ? /*
> + ? ? ? ?* Since the register values are computed and written within
> + ? ? ? ?* __omap_dm_timer_stop, we need to use read to retrieve the
> + ? ? ? ?* context.
> + ? ? ? ?*/
> + ? ? ? timer->context.tclr =
> + ? ? ? ? ? ? ? ? ? ? ? omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> + ? ? ? timer->context.tisr = __raw_readl(timer->irq_stat);
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>

I didn't review the whole patch, but at least this part is not in
mainline, it seems like the patch modified by Tony and the v16 were
not the same.

I could diff and include the missing parts, if someone can confirm
that we need v16, which I believe so, since current stop function
doesn't call omap_dm_timer_disable.

Regards,

Omar

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-11-15 17:57     ` Omar Ramirez Luna
@ 2011-11-16  6:18       ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-11-16  6:18 UTC (permalink / raw)
  To: Omar Ramirez Luna
  Cc: linux-omap, khilman, tony, linux-arm-kernel, Santosh Shilimkar

On Tue, Nov 15, 2011 at 11:27 PM, Omar Ramirez Luna <or.rmz1@gmail.com> wrote:
> Hi Tarun,
>
> On Tue, Sep 20, 2011 at 6:30 AM, Tarun Kanti DebBarma
> <tarun.kanti@ti.com> wrote:
>> 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.
>
> Now that handling of the clock has been decoupled from
> omap_dm_timer_request_specific/free and placed in start/stop
> functions, there is a "possible irq lock inversion dependency
> detected" for any attempt to enable the clock from soft|hard irq.
>
> My use case is as follows:
>
> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
> for processing the message, when it reaches tidspbridge it turns out
> that the DSP wants to enable a gpt timer; however, locks involved
> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
> have been called from unsafe contexts in the past
> (http://pastebin.com/7Dtz8t0f).
>
> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
The aim is to prevent client drivers perform clock enable/disable independently.
Instead just use the request/start/stop APIs. In that way we can make clock
enable/disable functions static in the future.
>
> ...
>> @@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
>>                rate = clk_get_rate(timer->fclk);
>>
>>        __omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
>> +
>> +       if (timer->loses_context) {
>> +               if (timer->get_context_loss_count)
>> +                       timer->ctx_loss_count =
>> +                       timer->get_context_loss_count(&timer->pdev->dev);
>> +       }
>> +
>> +       /*
>> +        * Since the register values are computed and written within
>> +        * __omap_dm_timer_stop, we need to use read to retrieve the
>> +        * context.
>> +        */
>> +       timer->context.tclr =
>> +                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>> +       timer->context.tisr = __raw_readl(timer->irq_stat);
>> +       omap_dm_timer_disable(timer);
>>  }
>>  EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>>
>
> I didn't review the whole patch, but at least this part is not in
> mainline, it seems like the patch modified by Tony and the v16 were
> not the same.
>
> I could diff and include the missing parts, if someone can confirm
> that we need v16, which I believe so, since current stop function
> doesn't call omap_dm_timer_disable.
You are right. This change some how got missed in mainline.
I have posted a patch for this already.
--
Tarun
>
> Regards,
>
> Omar
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-11-16  6:18       ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-11-16  6:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 15, 2011 at 11:27 PM, Omar Ramirez Luna <or.rmz1@gmail.com> wrote:
> Hi Tarun,
>
> On Tue, Sep 20, 2011 at 6:30 AM, Tarun Kanti DebBarma
> <tarun.kanti@ti.com> wrote:
>> 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.
>
> Now that handling of the clock has been decoupled from
> omap_dm_timer_request_specific/free and placed in start/stop
> functions, there is a "possible irq lock inversion dependency
> detected" for any attempt to enable the clock from soft|hard irq.
>
> My use case is as follows:
>
> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
> for processing the message, when it reaches tidspbridge it turns out
> that the DSP wants to enable a gpt timer; however, locks involved
> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
> have been called from unsafe contexts in the past
> (http://pastebin.com/7Dtz8t0f).
>
> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
The aim is to prevent client drivers perform clock enable/disable independently.
Instead just use the request/start/stop APIs. In that way we can make clock
enable/disable functions static in the future.
>
> ...
>> @@ -303,6 +342,22 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
>> ? ? ? ? ? ? ? ?rate = clk_get_rate(timer->fclk);
>>
>> ? ? ? ?__omap_dm_timer_stop(timer, timer->posted, rate, is_omap2);
>> +
>> + ? ? ? if (timer->loses_context) {
>> + ? ? ? ? ? ? ? if (timer->get_context_loss_count)
>> + ? ? ? ? ? ? ? ? ? ? ? timer->ctx_loss_count =
>> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
>> + ? ? ? }
>> +
>> + ? ? ? /*
>> + ? ? ? ?* Since the register values are computed and written within
>> + ? ? ? ?* __omap_dm_timer_stop, we need to use read to retrieve the
>> + ? ? ? ?* context.
>> + ? ? ? ?*/
>> + ? ? ? timer->context.tclr =
>> + ? ? ? ? ? ? ? ? ? ? ? omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
>> + ? ? ? timer->context.tisr = __raw_readl(timer->irq_stat);
>> + ? ? ? omap_dm_timer_disable(timer);
>> ?}
>> ?EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>>
>
> I didn't review the whole patch, but at least this part is not in
> mainline, it seems like the patch modified by Tony and the v16 were
> not the same.
>
> I could diff and include the missing parts, if someone can confirm
> that we need v16, which I believe so, since current stop function
> doesn't call omap_dm_timer_disable.
You are right. This change some how got missed in mainline.
I have posted a patch for this already.
--
Tarun
>
> Regards,
>
> Omar
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-11-16  6:18       ` DebBarma, Tarun Kanti
@ 2011-11-17  0:53         ` Omar Ramirez Luna
  -1 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-17  0:53 UTC (permalink / raw)
  To: DebBarma, Tarun Kanti
  Cc: linux-omap, khilman, tony, linux-arm-kernel, Santosh Shilimkar

On Wed, Nov 16, 2011 at 12:18 AM, DebBarma, Tarun Kanti
<tarun.kanti@ti.com> wrote:
...
>> My use case is as follows:
>>
>> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
>> for processing the message, when it reaches tidspbridge it turns out
>> that the DSP wants to enable a gpt timer; however, locks involved
>> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
>> have been called from unsafe contexts in the past
>> (http://pastebin.com/7Dtz8t0f).
>>
>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
> The aim is to prevent client drivers perform clock enable/disable independently.
> Instead just use the request/start/stop APIs. In that way we can make clock
> enable/disable functions static in the future.

Those are the APIs I'm using, omap_dm_timer_request_specific from a
softirq triggers this warning, this was not hinted by the patch or
cover letter of the series, hence the question:

Was this change intentional? Does omap_dm_timer_request_specific
should be allowed on other contexts (soft|hard irq)?

...
> You are right. This change some how got missed in mainline.
> I have posted a patch for this already.

Ok.

Regards,

Omar

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-11-17  0:53         ` Omar Ramirez Luna
  0 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-17  0:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2011 at 12:18 AM, DebBarma, Tarun Kanti
<tarun.kanti@ti.com> wrote:
...
>> My use case is as follows:
>>
>> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
>> for processing the message, when it reaches tidspbridge it turns out
>> that the DSP wants to enable a gpt timer; however, locks involved
>> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
>> have been called from unsafe contexts in the past
>> (http://pastebin.com/7Dtz8t0f).
>>
>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
> The aim is to prevent client drivers perform clock enable/disable independently.
> Instead just use the request/start/stop APIs. In that way we can make clock
> enable/disable functions static in the future.

Those are the APIs I'm using, omap_dm_timer_request_specific from a
softirq triggers this warning, this was not hinted by the patch or
cover letter of the series, hence the question:

Was this change intentional? Does omap_dm_timer_request_specific
should be allowed on other contexts (soft|hard irq)?

...
> You are right. This change some how got missed in mainline.
> I have posted a patch for this already.

Ok.

Regards,

Omar

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-11-17  0:53         ` Omar Ramirez Luna
@ 2011-11-17  9:42           ` DebBarma, Tarun Kanti
  -1 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-11-17  9:42 UTC (permalink / raw)
  To: Omar Ramirez Luna
  Cc: linux-omap, khilman, tony, linux-arm-kernel, Santosh Shilimkar

On Thu, Nov 17, 2011 at 6:23 AM, Omar Ramirez Luna <or.rmz1@gmail.com> wrote:
> On Wed, Nov 16, 2011 at 12:18 AM, DebBarma, Tarun Kanti
> <tarun.kanti@ti.com> wrote:
> ...
>>> My use case is as follows:
>>>
>>> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
>>> for processing the message, when it reaches tidspbridge it turns out
>>> that the DSP wants to enable a gpt timer; however, locks involved
>>> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
>>> have been called from unsafe contexts in the past
>>> (http://pastebin.com/7Dtz8t0f).
>>>
>>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
>> The aim is to prevent client drivers perform clock enable/disable independently.
>> Instead just use the request/start/stop APIs. In that way we can make clock
>> enable/disable functions static in the future.
>
> Those are the APIs I'm using, omap_dm_timer_request_specific from a
> softirq triggers this warning, this was not hinted by the patch or
> cover letter of the series, hence the question:
>
> Was this change intentional? Does omap_dm_timer_request_specific
> should be allowed on other contexts (soft|hard irq)?
omap_dm_timer_request_specific() uses spin_lock_irqsave and
spin_unlock_irqrestore
to protect the timer list. There is nothing specific to prevent this
function from being
called from interrupt context. But you probably have to be careful to
avoid deadlock
in the interrupt context by disabling interrupts appropriately so that
we avoid trying
to re-acquire the lock. If you send me the code snippet I can have a look.
--
Tarun
>
> ...
>> You are right. This change some how got missed in mainline.
>> I have posted a patch for this already.
>
> Ok.
>
> Regards,
>
> Omar
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-11-17  9:42           ` DebBarma, Tarun Kanti
  0 siblings, 0 replies; 76+ messages in thread
From: DebBarma, Tarun Kanti @ 2011-11-17  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 17, 2011 at 6:23 AM, Omar Ramirez Luna <or.rmz1@gmail.com> wrote:
> On Wed, Nov 16, 2011 at 12:18 AM, DebBarma, Tarun Kanti
> <tarun.kanti@ti.com> wrote:
> ...
>>> My use case is as follows:
>>>
>>> DSP sends a mailbox message to ARM, this triggers a tasklet in mailbox
>>> for processing the message, when it reaches tidspbridge it turns out
>>> that the DSP wants to enable a gpt timer; however, locks involved
>>> "clocks_mutex" and "dm_timer_lock" now could cause a deadlock as they
>>> have been called from unsafe contexts in the past
>>> (http://pastebin.com/7Dtz8t0f).
>>>
>>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
>> The aim is to prevent client drivers perform clock enable/disable independently.
>> Instead just use the request/start/stop APIs. In that way we can make clock
>> enable/disable functions static in the future.
>
> Those are the APIs I'm using, omap_dm_timer_request_specific from a
> softirq triggers this warning, this was not hinted by the patch or
> cover letter of the series, hence the question:
>
> Was this change intentional? Does omap_dm_timer_request_specific
> should be allowed on other contexts (soft|hard irq)?
omap_dm_timer_request_specific() uses spin_lock_irqsave and
spin_unlock_irqrestore
to protect the timer list. There is nothing specific to prevent this
function from being
called from interrupt context. But you probably have to be careful to
avoid deadlock
in the interrupt context by disabling interrupts appropriately so that
we avoid trying
to re-acquire the lock. If you send me the code snippet I can have a look.
--
Tarun
>
> ...
>> You are right. This change some how got missed in mainline.
>> I have posted a patch for this already.
>
> Ok.
>
> Regards,
>
> Omar
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
  2011-11-17  9:42           ` DebBarma, Tarun Kanti
@ 2011-11-18  2:19             ` Omar Ramirez Luna
  -1 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-18  2:19 UTC (permalink / raw)
  To: DebBarma, Tarun Kanti
  Cc: linux-omap, khilman, tony, linux-arm-kernel, Santosh Shilimkar

On Thu, Nov 17, 2011 at 3:42 AM, DebBarma, Tarun Kanti
<tarun.kanti@ti.com> wrote:
...
>>>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
>>> The aim is to prevent client drivers perform clock enable/disable independently.
>>> Instead just use the request/start/stop APIs. In that way we can make clock
>>> enable/disable functions static in the future.
>>
>> Those are the APIs I'm using, omap_dm_timer_request_specific from a
>> softirq triggers this warning, this was not hinted by the patch or
>> cover letter of the series, hence the question:
>>
>> Was this change intentional? Does omap_dm_timer_request_specific
>> should be allowed on other contexts (soft|hard irq)?
> omap_dm_timer_request_specific() uses spin_lock_irqsave and
> spin_unlock_irqrestore
> to protect the timer list. There is nothing specific to prevent this
> function from being
> called from interrupt context. But you probably have to be careful to
> avoid deadlock
> in the interrupt context by disabling interrupts appropriately so that
> we avoid trying
> to re-acquire the lock.

? ...interrupt context should have interrupts disabled.

>If you send me the code snippet I can have a look.

Here it is a module that triggers this:

http://pastebin.com/bfcWtmQp

Please apply this patch too, otherwise OOT modules disable lockdep:

http://comments.gmane.org/gmane.linux.kernel/1216036

Also enable Schedule-while-atomic checks as this triggers errors even
on process context, I have prepared a patch for those, will submit
soon.

And BTW, these errors are seen since patch "ARM: OMAP: dmtimer:
switch-over to platform device driver", where code to do clk_get was
placed under spin_lock_irqsave, clk_get is the one holding a
mutex_lock which can't be done under a spin_lock.

Regards,

Omar

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
@ 2011-11-18  2:19             ` Omar Ramirez Luna
  0 siblings, 0 replies; 76+ messages in thread
From: Omar Ramirez Luna @ 2011-11-18  2:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 17, 2011 at 3:42 AM, DebBarma, Tarun Kanti
<tarun.kanti@ti.com> wrote:
...
>>>> Is the intention to restrict enabling the dmtimer clocks from hard|soft irqs?
>>> The aim is to prevent client drivers perform clock enable/disable independently.
>>> Instead just use the request/start/stop APIs. In that way we can make clock
>>> enable/disable functions static in the future.
>>
>> Those are the APIs I'm using, omap_dm_timer_request_specific from a
>> softirq triggers this warning, this was not hinted by the patch or
>> cover letter of the series, hence the question:
>>
>> Was this change intentional? Does omap_dm_timer_request_specific
>> should be allowed on other contexts (soft|hard irq)?
> omap_dm_timer_request_specific() uses spin_lock_irqsave and
> spin_unlock_irqrestore
> to protect the timer list. There is nothing specific to prevent this
> function from being
> called from interrupt context. But you probably have to be careful to
> avoid deadlock
> in the interrupt context by disabling interrupts appropriately so that
> we avoid trying
> to re-acquire the lock.

? ...interrupt context should have interrupts disabled.

>If you send me the code snippet I can have a look.

Here it is a module that triggers this:

http://pastebin.com/bfcWtmQp

Please apply this patch too, otherwise OOT modules disable lockdep:

http://comments.gmane.org/gmane.linux.kernel/1216036

Also enable Schedule-while-atomic checks as this triggers errors even
on process context, I have prepared a patch for those, will submit
soon.

And BTW, these errors are seen since patch "ARM: OMAP: dmtimer:
switch-over to platform device driver", where code to do clk_get was
placed under spin_lock_irqsave, clk_get is the one holding a
mutex_lock which can't be done under a spin_lock.

Regards,

Omar

^ permalink raw reply	[flat|nested] 76+ messages in thread

end of thread, other threads:[~2011-11-18  2:19 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-20 11:30 [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver Tarun Kanti DebBarma
2011-09-20 11:30 ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  5:58     ` DebBarma, Tarun Kanti
2011-09-22  5:58       ` DebBarma, Tarun Kanti
2011-09-20 11:30 ` [PATCH v16 02/12] OMAP1: dmtimer: conversion to platform devices Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 03/12] OMAP2+: dmtimer: convert " Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 04/12] OMAP: dmtimer: platform driver Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  5:57     ` DebBarma, Tarun Kanti
2011-09-22  5:57       ` DebBarma, Tarun Kanti
2011-09-20 11:30 ` [PATCH v16 06/12] OMAP: dmtimer: pm_runtime support Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  5:53     ` DebBarma, Tarun Kanti
2011-09-22  5:53       ` DebBarma, Tarun Kanti
2011-09-20 11:30 ` [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  6:05     ` DebBarma, Tarun Kanti
2011-09-22  6:05       ` DebBarma, Tarun Kanti
2011-09-20 11:30 ` [PATCH v16 09/12] OMAP: dmtimer: low-power mode support Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  6:07     ` DebBarma, Tarun Kanti
2011-09-22  6:07       ` DebBarma, Tarun Kanti
2011-11-15 17:57   ` Omar Ramirez Luna
2011-11-15 17:57     ` Omar Ramirez Luna
2011-11-16  6:18     ` DebBarma, Tarun Kanti
2011-11-16  6:18       ` DebBarma, Tarun Kanti
2011-11-17  0:53       ` Omar Ramirez Luna
2011-11-17  0:53         ` Omar Ramirez Luna
2011-11-17  9:42         ` DebBarma, Tarun Kanti
2011-11-17  9:42           ` DebBarma, Tarun Kanti
2011-11-18  2:19           ` Omar Ramirez Luna
2011-11-18  2:19             ` Omar Ramirez Luna
2011-09-20 11:30 ` [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  0:42   ` Tony Lindgren
2011-09-22  0:42     ` Tony Lindgren
2011-09-22  6:00     ` DebBarma, Tarun Kanti
2011-09-22  6:00       ` DebBarma, Tarun Kanti
2011-09-20 11:30 ` [PATCH v16 11/12] OMAP: dmtimer: add error handling to export APIs Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-20 11:30 ` [PATCH v16 12/12] OMAP: dmtimer: get rid of timer_ip_version field Tarun Kanti DebBarma
2011-09-20 11:30   ` Tarun Kanti DebBarma
2011-09-22  1:00   ` Tony Lindgren
2011-09-22  1:00     ` Tony Lindgren
2011-09-22  0:59 ` [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver Tony Lindgren
2011-09-22  0:59   ` Tony Lindgren
2011-09-22  6:09   ` DebBarma, Tarun Kanti
2011-09-22  6:09     ` DebBarma, Tarun Kanti
2011-09-23  9:27     ` DebBarma, Tarun Kanti
2011-09-23  9:27       ` DebBarma, Tarun Kanti
2011-09-26 17:25       ` Tony Lindgren
2011-09-26 17:25         ` Tony Lindgren
2011-09-26 18:38         ` DebBarma, Tarun Kanti
2011-09-26 18:38           ` DebBarma, Tarun Kanti
2011-10-03 14:33 ` Cousson, Benoit
2011-10-03 14:33   ` Cousson, Benoit
2011-10-04  0:36   ` Tony Lindgren
2011-10-04  0:36     ` Tony Lindgren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.