clockevents: new material for 3.16
Subsystems (8)
Hi Thomas, Ingo,
this time we have a big number of changes in the clockevents.
There is a branch shared between Simon and I with two merges. The first merge was to pull the cmt,mtu changes from Laurent into the clockevents/cmt-mtu2-tmu-cleanups branch. Then this one has been merged in the clockevents/3.16. A bit later, a new fix on top of these changes has been provided and applied to clockevents/cmt-mtu2-tmu-cleanups with a second merge to clockevents/3.16.
clockevents/cmt-mtu2-tmu-cleanups will stay there until the 3.16 is released.
This pull request contains the following changes:
* Laurent Pinchart did a lot of modifications to prepare the DT
support. These modifications include a lot of cleanup (structure renaming, preparation to support multiple channel, kzalloc usage, ...) and then finishes to drop the old code to the new one.
* Jingoo Han removed the dev_err when an allocation fails because this
error is already given by the mm subsystems.
* http://patchwork.ozlabs.org/patch/324158/
* [conflict resolved] kmalloc => kzalloc changes with cmt,tmu,
mtu cleanups from Laurent Pinchard
* Matthew Leach added the ARM global timer with vexpress, enabled the
ARM global timer with the A5 and added the definition in the DT. He also fixed a invalid check when looking for an usable ARM global timer for A9
* Maxime Ripard added the support for AllWinner A31 for sun4i and made
the timer reset optional through the DT
* Stephen Boyd used the msm timer for the udelay
* Uwe Kleine-König fixed the non-standard 'compatible' binding for efm32
* Xiubo Li clarified the types for the clocksource_mmio_read* and
added a new Flextimer Module (FTM) with its bindings
* Yang Wei added the 'notrace' attribute to 'read_sched_clock' for thedw_apb_timer
The following changes since commit 2779ac167b1a1bf8153dca9f3a141c6148c6b89f:
timer_stats/doc: Fix /proc/timer_stats documentation (2014-05-04
20:46:32 +0200)
are available in the git repository at:
git://git.linaro.org/people/daniel.lezcano/linux.git clockevents/3.16
for you to fetch changes up to 2529c3a330797000d699d70c9a65b8525c6652de:
clocksource: Add Freescale FlexTimer Module (FTM) timer support
(2014-05-23 10:12:04 +0200)
----------------------------------------------------------------
Daniel Lezcano (3):
Merge branch 'clockevents/cmt-mtu2-tmu-cleanups' into
clockevents/3.16
Merge remote-tracking branch 'tip/timers/core/timers/core' into
clockevents/3.16
Merge branch 'clockevents/cmt-mtu2-tmu-cleanups' into
clockevents/3.16
Jingoo Han (4):
clocksource: em_sti: Remove unnecessary OOM messages
clocksource: sh_cmt: Remove unnecessary OOM messages
clocksource: sh_mtu2: Remove unnecessary OOM messages
clocksource: sh_tmu: Remove unnecessary OOM messages
Laurent Pinchart (53):
clocksource: sh_cmt: Use request_irq() instead of setup_irq()
clocksource: sh_cmt: Split channel fields from sh_cmt_priv
clocksource: sh_cmt: Rename struct sh_cmt_priv to sh_cmt_device
clocksource: sh_cmt: Split channel setup to separate function
clocksource: sh_cmt: Constify name argument to sh_cmt_register()
clocksource: sh_cmt: Rename mapbase/mapbase_str to mapbase_ch/mapbase
clocksource: sh_cmt: Add memory base to sh_cmt_channel structure
clocksource: sh_cmt: Add index to struct sh_cmt_channel
clocksource: sh_cmt: Replace kmalloc + memset with kzalloc
clocksource: sh_cmt: Allocate channels dynamically
clocksource: sh_cmt: Split static information from sh_cmt_device
clocksource: sh_cmt: Replace hardcoded register values with macros
clocksource: sh_cmt: Set cpumask to cpu_possible_mask
clocksource: sh_cmt: Hardcode CMT clock event rating to 125
clocksource: sh_cmt: Hardcode CMT clock source rating to 125
clocksource: sh_cmt: Add support for multiple channels per device
clocksource: sh_cmt: Rename clock to "fck" in the non-legacy case
clocksource: sh_cmt: Remove FSF mail address from GPL notice
clocksource: sh_cmt: Sort headers alphabetically
clocksource: sh_cmt: Request IRQ for clock event device only
clocksource: sh_tmu: Use request_irq() instead of setup_irq()
clocksource: sh_tmu: Split channel fields from sh_tmu_priv
clocksource: sh_tmu: Rename struct sh_tmu_priv to sh_tmu_device
clocksource: sh_tmu: Split channel setup to separate function
clocksource: sh_tmu: Constify name argument to sh_tmu_register()
clocksource: sh_tmu: Add memory base to sh_tmu_channel structure
clocksource: sh_tmu: Add index to struct sh_tmu_channel
clocksource: sh_tmu: Replace kmalloc + memset with kzalloc
clocksource: sh_tmu: Allocate channels dynamically
clocksource: sh_tmu: Replace hardcoded register values with macros
clocksource: sh_tmu: Hardcode TMU clock event and source ratings
to 200
clocksource: sh_tmu: Add support for multiple channels per device
clocksource: sh_tmu: Rename clock to "fck" in the non-legacy case
clocksource: sh_tmu: Remove FSF mail address from GPL notice
clocksource: sh_tmu: Sort headers alphabetically
clocksource: sh_mtu2: Use request_irq() instead of setup_irq()
clocksource: sh_mtu2: Turn sh_mtu2_priv fields into local variables
clocksource: sh_mtu2: Split channel fields from sh_mtu2_priv
clocksource: sh_mtu2: Rename struct sh_mtu2_priv to sh_mtu2_device
clocksource: sh_mtu2: Split channel setup to separate function
clocksource: sh_mtu2: Constify name argument to sh_mtu2_register()
clocksource: sh_mtu2: Add memory base to sh_mtu2_channel structure
clocksource: sh_mtu2: Add index to struct sh_mtu2_channel
clocksource: sh_mtu2: Replace kmalloc + memset with kzalloc
clocksource: sh_mtu2: Allocate channels dynamically
clocksource: sh_mtu2: Replace hardcoded register values with macros
clocksource: sh_mtu2: Set cpumask to cpu_possible_mask
clocksource: sh_mtu2: Hardcode MTU2 clock event rating to 200
clocksource: sh_mtu2: Add support for multiple channels per device
clocksource: sh_mtu2: Rename clock to "fck" in the non-legacy case
clocksource: sh_mtu2: Remove FSF mail address from GPL notice
clocksource: sh_mtu2: Sort headers alphabetically
clocksource: sh_tmu: Fix channel IRQ retrieval in legacy case
Matthew Leach (4):
clocksource: arm_global_timer: Only check for unusable timer on A9
documentaion: DT: allow a A5 compatible string in global timer
dts: ca5: add the global timer for the A5
KConfig: Vexpress: build the ARM_GLOBAL_TIMER with vexpress platform
Maxime Ripard (2):
clocksource: sun5i: Add support for reset controller
ARM: sun6i: a31: Add support for the High Speed Timers
Stephen Boyd (1):
clocksource: qcom: Implement read_current_timer for udelay
Uwe Kleine-König (1):
clocksource: efm32: use $vendor,$device scheme for compatible string
Xiubo Li (5):
clocksource: Fix type confusion for clocksource_mmio_readX_Y
clocksource: Fix clocksource_mmio_readX_down
clocksource: ftm: Add FlexTimer Module (FTM) Timer devicetree
Documentation
ARM: dts: vf610: Add Freescale FlexTimer Module timer node.
clocksource: Add Freescale FlexTimer Module (FTM) timer support
Yang Wei (1):
clocksource: dw_apb_timer_of: Do not trace read_sched_clock
.../devicetree/bindings/arm/global_timer.txt | 7 +-
.../bindings/timer/allwinner,sun5i-a13-hstimer.txt | 4 +
...efm32,timer.txt => energymicro,efm32-timer.txt} | 4 +-
.../devicetree/bindings/timer/fsl,ftm-timer.txt | 31 +
arch/arm/boot/dts/sun6i-a31.dtsi | 11 +
arch/arm/boot/dts/vexpress-v2p-ca5s.dts | 10 +-
arch/arm/boot/dts/vf610.dtsi | 13 +
arch/arm/mach-vexpress/Kconfig | 1 +
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/arm_global_timer.c | 5 +-
drivers/clocksource/dw_apb_timer_of.c | 2 +-
drivers/clocksource/em_sti.c | 4 +-
drivers/clocksource/fsl_ftm_timer.c | 367 ++++++++
drivers/clocksource/mmio.c | 8 +-
drivers/clocksource/qcom-timer.c | 13 +
drivers/clocksource/sh_cmt.c | 958
+++++++++++++-------
drivers/clocksource/sh_mtu2.c | 490 +++++++---
drivers/clocksource/sh_tmu.c | 543 ++++++-----
drivers/clocksource/time-efm32.c | 3 +-
drivers/clocksource/timer-sun5i.c | 6 +
include/linux/sh_timer.h | 1 +
22 files changed, 1785 insertions(+), 702 deletions(-)
rename Documentation/devicetree/bindings/timer/{efm32,timer.txt =>
energymicro,efm32-timer.txt} (87%)
create mode 100644
Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt
create mode 100644 drivers/clocksource/fsl_ftm_timer.cSignature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
PATCH 1/71 clocksource: sh_cmt: Use request_irq() instead of setup_irq()
From: Laurent Pinchart <[email protected]>
The driver claims it needs to register an interrupt handler too early for request_irq(). This might have been true in the past, but the only meaningful difference between request_irq() and setup_irq() today is an additional kzalloc() call in request_irq(). As the driver calls kmalloc() itself we know that the slab allocator is available, we can thus switch to request_irq().
--- drivers/clocksource/sh_cmt.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/clocksource/sh_cmt.c +3 -7
@@ -728,12 +728,6 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err1; } -/* request irq using setup_irq() (too early for request_irq()) */ - p->irqaction.name =dev_name (&p->pdev->dev); - p->irqaction.handler = sh_cmt_interrupt; - p->irqaction.dev_id = p; - p->irqaction.flags =IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING ; -/* get hold of clock */ p->clk =clk_get (&p->pdev->dev,"cmt_fck" );if (IS_ERR (p->clk)) {
@@ -786,7 +780,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) } p->cs_enabled = false; - ret =setup_irq (irq, &p->irqaction); + ret =request_irq (irq, sh_cmt_interrupt, +IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , +dev_name (&p->pdev->dev), p);if (ret) {dev_err (&p->pdev->dev,"failed to request irq %d\n" , irq); goto err4;
Signature · 1 line
1.7.9.5
PATCH 2/71 clocksource: sh_cmt: Split channel fields from sh_cmt_priv
From: Laurent Pinchart <[email protected]>
Create a new sh_cmt_channel structure to hold the channel-specific field in preparation for multiple channels per device support.
--- drivers/clocksource/sh_cmt.c | 385 ++++++++++++++++++++++-------------------- 1 file changed, 199 insertions(+), 186 deletions(-)
drivers/clocksource/sh_cmt.c +199 -186
@@ -35,15 +35,10 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> -struct sh_cmt_priv { -void __iomem *mapbase; -void __iomem *mapbase_str; -struct clk *clk; -unsigned long width;/* 16 or 32 bit version of hardware block */ -unsigned long overflow_bit; -unsigned long clear_bits; -struct irqaction irqaction; -struct platform_device *pdev; +struct sh_cmt_priv ; + +struct sh_cmt_channel { +struct sh_cmt_priv *cmt;unsigned long flags;unsigned long match_value;
@@ -55,6 +50,20 @@ struct sh_cmt_priv {struct clocksource cs;unsigned long total_cycles;bool cs_enabled; +}; + +struct sh_cmt_priv { +struct platform_device *pdev; + +void __iomem *mapbase; +void __iomem *mapbase_str; +struct clk *clk; + +struct sh_cmt_channel channel; + +unsigned long width;/* 16 or 32 bit version of hardware block */ +unsigned long overflow_bit; +unsigned long clear_bits;/* callbacks for CMSTR and CMCSR access */ unsigned long (*read_control)(void __iomem *base,unsigned long offs);
@@ -114,60 +123,60 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,#define CMCNT 1/* channel register */ #define CMCOR 2/* channel register */ -static inline unsigned long sh_cmt_read_cmstr (struct sh_cmt_priv *p) +static inline unsigned long sh_cmt_read_cmstr (struct sh_cmt_channel *ch) { -return p->read_control (p->mapbase_str,0 ); +return ch->cmt->read_control (ch->cmt->mapbase_str,0 ); } -static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_priv *p) +static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) { -return p->read_control (p->mapbase,CMCSR ); +return ch->cmt->read_control (ch->cmt->mapbase,CMCSR ); } -static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_priv *p) +static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) { -return p->read_count (p->mapbase,CMCNT ); +return ch->cmt->read_count (ch->cmt->mapbase,CMCNT ); } -static inline void sh_cmt_write_cmstr (struct sh_cmt_priv *p, +static inline void sh_cmt_write_cmstr (struct sh_cmt_channel *ch,unsigned long value) { - p->write_control (p->mapbase_str,0 , value); + ch->cmt->write_control (ch->cmt->mapbase_str,0 , value); } -static inline void sh_cmt_write_cmcsr (struct sh_cmt_priv *p, +static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch,unsigned long value) { - p->write_control (p->mapbase,CMCSR , value); + ch->cmt->write_control (ch->cmt->mapbase,CMCSR , value); } -static inline void sh_cmt_write_cmcnt (struct sh_cmt_priv *p, +static inline void sh_cmt_write_cmcnt (struct sh_cmt_channel *ch,unsigned long value) { - p->write_count (p->mapbase,CMCNT , value); + ch->cmt->write_count (ch->cmt->mapbase,CMCNT , value); } -static inline void sh_cmt_write_cmcor (struct sh_cmt_priv *p, +static inline void sh_cmt_write_cmcor (struct sh_cmt_channel *ch,unsigned long value) { - p->write_count (p->mapbase,CMCOR , value); + ch->cmt->write_count (ch->cmt->mapbase,CMCOR , value); } -static unsigned long sh_cmt_get_counter (struct sh_cmt_priv *p, +static unsigned long sh_cmt_get_counter (struct sh_cmt_channel *ch,int *has_wrapped) {unsigned long v1, v2, v3;int o1, o2; - o1 =sh_cmt_read_cmcsr (p) & p->overflow_bit; + o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->overflow_bit;/* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { o2 = o1; - v1 =sh_cmt_read_cmcnt (p); - v2 =sh_cmt_read_cmcnt (p); - v3 =sh_cmt_read_cmcnt (p); - o1 =sh_cmt_read_cmcsr (p) & p->overflow_bit; + v1 =sh_cmt_read_cmcnt (ch); + v2 =sh_cmt_read_cmcnt (ch); + v3 =sh_cmt_read_cmcnt (ch); + o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->overflow_bit; }while (unlikely ((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
@@ -177,52 +186,52 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,static DEFINE_RAW_SPINLOCK (sh_cmt_lock); -static void sh_cmt_start_stop_ch (struct sh_cmt_priv *p,int start) +static void sh_cmt_start_stop_ch (struct sh_cmt_channel *ch,int start) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; +struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */ raw_spin_lock_irqsave (&sh_cmt_lock, flags); - value =sh_cmt_read_cmstr (p); + value =sh_cmt_read_cmstr (ch);if (start) value |=1 << cfg->timer_bit;else value &= ~(1 << cfg->timer_bit); -sh_cmt_write_cmstr (p, value); +sh_cmt_write_cmstr (ch, value);raw_spin_unlock_irqrestore (&sh_cmt_lock, flags); } -static int sh_cmt_enable (struct sh_cmt_priv *p,unsigned long *rate) +static int sh_cmt_enable (struct sh_cmt_channel *ch,unsigned long *rate) {int k, ret; -pm_runtime_get_sync (&p->pdev->dev); -dev_pm_syscore_device (&p->pdev->dev, true); +pm_runtime_get_sync (&ch->cmt->pdev->dev); +dev_pm_syscore_device (&ch->cmt->pdev->dev, true);/* enable clock */ - ret =clk_enable (p->clk); + ret =clk_enable (ch->cmt->clk);if (ret) { -dev_err (&p->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->cmt->pdev->dev,"cannot enable clock\n" ); goto err0; }/* make sure channel is disabled */ -sh_cmt_start_stop_ch (p,0 ); +sh_cmt_start_stop_ch (ch,0 );/* configure channel, periodic mode and maximum timeout */ -if (p->width ==16 ) { - *rate =clk_get_rate (p->clk) /512 ; -sh_cmt_write_cmcsr (p,0x43 ); +if (ch->cmt->width ==16 ) { + *rate =clk_get_rate (ch->cmt->clk) /512 ; +sh_cmt_write_cmcsr (ch,0x43 ); }else { - *rate =clk_get_rate (p->clk) /8 ; -sh_cmt_write_cmcsr (p,0x01a4 ); + *rate =clk_get_rate (ch->cmt->clk) /8 ; +sh_cmt_write_cmcsr (ch,0x01a4 ); } -sh_cmt_write_cmcor (p,0xffffffff ); -sh_cmt_write_cmcnt (p,0 ); +sh_cmt_write_cmcor (ch,0xffffffff ); +sh_cmt_write_cmcnt (ch,0 );/* * According to the sh73a0 user's manual, as CMCNT can be operated
@@ -236,41 +245,41 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)* take RCLKx2 at maximum. */ for (k =0 ; k <100 ; k++) { -if (!sh_cmt_read_cmcnt (p)) +if (!sh_cmt_read_cmcnt (ch))break ;udelay (1 ); } -if (sh_cmt_read_cmcnt (p)) { -dev_err (&p->pdev->dev,"cannot clear CMCNT\n" ); +if (sh_cmt_read_cmcnt (ch)) { +dev_err (&ch->cmt->pdev->dev,"cannot clear CMCNT\n" ); ret = -ETIMEDOUT ; goto err1; }/* enable channel */ -sh_cmt_start_stop_ch (p,1 ); +sh_cmt_start_stop_ch (ch,1 );return 0 ; err1:/* stop clock */ -clk_disable (p->clk); +clk_disable (ch->cmt->clk); err0:return ret; } -static void sh_cmt_disable (struct sh_cmt_priv *p) +static void sh_cmt_disable (struct sh_cmt_channel *ch) {/* disable channel */ -sh_cmt_start_stop_ch (p,0 ); +sh_cmt_start_stop_ch (ch,0 );/* disable interrupts in CMT block */ -sh_cmt_write_cmcsr (p,0 ); +sh_cmt_write_cmcsr (ch,0 );/* stop clock */ -clk_disable (p->clk); +clk_disable (ch->cmt->clk); -dev_pm_syscore_device (&p->pdev->dev, false); -pm_runtime_put (&p->pdev->dev); +dev_pm_syscore_device (&ch->cmt->pdev->dev, false); +pm_runtime_put (&ch->cmt->pdev->dev); }/* private flags */
@@ -280,24 +289,24 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)#define FLAG_SKIPEVENT (1 << 3)#define FLAG_IRQCONTEXT (1 << 4) -static void sh_cmt_clock_event_program_verify (struct sh_cmt_priv *p, +static void sh_cmt_clock_event_program_verify (struct sh_cmt_channel *ch,int absolute) {unsigned long new_match; -unsigned long value = p->next_match_value; +unsigned long value = ch->next_match_value;unsigned long delay =0 ;unsigned long now =0 ;int has_wrapped; - now =sh_cmt_get_counter (p, &has_wrapped); - p->flags |=FLAG_REPROGRAM ;/* force reprogram */ + now =sh_cmt_get_counter (ch, &has_wrapped); + ch->flags |=FLAG_REPROGRAM ;/* force reprogram */ if (has_wrapped) {/* we're competing with the interrupt handler. * -> let the interrupt handler reprogram the timer. * -> interrupt number two handles the event. */ - p->flags |=FLAG_SKIPEVENT ; + ch->flags |=FLAG_SKIPEVENT ;return ; }
@@ -309,20 +318,20 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,* but don't save the new match value yet. */ new_match = now + value + delay; -if (new_match > p->max_match_value) - new_match = p->max_match_value; +if (new_match > ch->max_match_value) + new_match = ch->max_match_value; -sh_cmt_write_cmcor (p, new_match); +sh_cmt_write_cmcor (ch, new_match); - now =sh_cmt_get_counter (p, &has_wrapped); -if (has_wrapped && (new_match > p->match_value)) { + now =sh_cmt_get_counter (ch, &has_wrapped); +if (has_wrapped && (new_match > ch->match_value)) {/* we are changing to a greater match value, * so this wrap must be caused by the counter * matching the old value. * -> first interrupt reprograms the timer. * -> interrupt number two handles the event. */ - p->flags |=FLAG_SKIPEVENT ; + ch->flags |=FLAG_SKIPEVENT ;break ; }
@@ -333,7 +342,7 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,* -> save programmed match value. * -> let isr handle the event. */ - p->match_value = new_match; + ch->match_value = new_match;break ; }
@@ -344,7 +353,7 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,* -> save programmed match value. * -> let isr handle the event. */ - p->match_value = new_match; + ch->match_value = new_match;break ; }
@@ -360,138 +369,138 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, delay =1 ;if (!delay) -dev_warn (&p->pdev->dev,"too long delay\n" ); +dev_warn (&ch->cmt->pdev->dev,"too long delay\n" ); }while (delay); } -static void __sh_cmt_set_next (struct sh_cmt_priv *p,unsigned long delta) +static void __sh_cmt_set_next (struct sh_cmt_channel *ch,unsigned long delta) { -if (delta > p->max_match_value) -dev_warn (&p->pdev->dev,"delta out of range\n" ); +if (delta > ch->max_match_value) +dev_warn (&ch->cmt->pdev->dev,"delta out of range\n" ); - p->next_match_value = delta; -sh_cmt_clock_event_program_verify (p,0 ); + ch->next_match_value = delta; +sh_cmt_clock_event_program_verify (ch,0 ); } -static void sh_cmt_set_next (struct sh_cmt_priv *p,unsigned long delta) +static void sh_cmt_set_next (struct sh_cmt_channel *ch,unsigned long delta) {unsigned long flags; -raw_spin_lock_irqsave (&p->lock, flags); -__sh_cmt_set_next (p, delta); -raw_spin_unlock_irqrestore (&p->lock, flags); +raw_spin_lock_irqsave (&ch->lock, flags); +__sh_cmt_set_next (ch, delta); +raw_spin_unlock_irqrestore (&ch->lock, flags); }static irqreturn_t sh_cmt_interrupt (int irq,void *dev_id) { -struct sh_cmt_priv *p = dev_id; +struct sh_cmt_channel *ch = dev_id;/* clear flags */ -sh_cmt_write_cmcsr (p,sh_cmt_read_cmcsr (p) & p->clear_bits); +sh_cmt_write_cmcsr (ch,sh_cmt_read_cmcsr (ch) & ch->cmt->clear_bits);/* update clock source counter to begin with if enabled * the wrap flag should be cleared by the timer specific * isr before we end up here. */ -if (p->flags &FLAG_CLOCKSOURCE ) - p->total_cycles += p->match_value +1 ; +if (ch->flags &FLAG_CLOCKSOURCE ) + ch->total_cycles += ch->match_value +1 ; -if (!(p->flags &FLAG_REPROGRAM )) - p->next_match_value = p->max_match_value; +if (!(ch->flags &FLAG_REPROGRAM )) + ch->next_match_value = ch->max_match_value; - p->flags |=FLAG_IRQCONTEXT ; + ch->flags |=FLAG_IRQCONTEXT ; -if (p->flags &FLAG_CLOCKEVENT ) { -if (!(p->flags &FLAG_SKIPEVENT )) { -if (p->ced.mode ==CLOCK_EVT_MODE_ONESHOT ) { - p->next_match_value = p->max_match_value; - p->flags |=FLAG_REPROGRAM ; +if (ch->flags &FLAG_CLOCKEVENT ) { +if (!(ch->flags &FLAG_SKIPEVENT )) { +if (ch->ced.mode ==CLOCK_EVT_MODE_ONESHOT ) { + ch->next_match_value = ch->max_match_value; + ch->flags |=FLAG_REPROGRAM ; } - p->ced.event_handler (&p->ced); + ch->ced.event_handler (&ch->ced); } } - p->flags &= ~FLAG_SKIPEVENT ; + ch->flags &= ~FLAG_SKIPEVENT ; -if (p->flags &FLAG_REPROGRAM ) { - p->flags &= ~FLAG_REPROGRAM ; -sh_cmt_clock_event_program_verify (p,1 ); +if (ch->flags &FLAG_REPROGRAM ) { + ch->flags &= ~FLAG_REPROGRAM ; +sh_cmt_clock_event_program_verify (ch,1 ); -if (p->flags &FLAG_CLOCKEVENT ) -if ((p->ced.mode ==CLOCK_EVT_MODE_SHUTDOWN ) - || (p->match_value == p->next_match_value)) - p->flags &= ~FLAG_REPROGRAM ; +if (ch->flags &FLAG_CLOCKEVENT ) +if ((ch->ced.mode ==CLOCK_EVT_MODE_SHUTDOWN ) + || (ch->match_value == ch->next_match_value)) + ch->flags &= ~FLAG_REPROGRAM ; } - p->flags &= ~FLAG_IRQCONTEXT ; + ch->flags &= ~FLAG_IRQCONTEXT ;return IRQ_HANDLED ; } -static int sh_cmt_start (struct sh_cmt_priv *p,unsigned long flag) +static int sh_cmt_start (struct sh_cmt_channel *ch,unsigned long flag) {int ret =0 ;unsigned long flags; -raw_spin_lock_irqsave (&p->lock, flags); +raw_spin_lock_irqsave (&ch->lock, flags); -if (!(p->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ))) - ret =sh_cmt_enable (p, &p->rate); +if (!(ch->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ))) + ret =sh_cmt_enable (ch, &ch->rate);if (ret) goto out; - p->flags |= flag; + ch->flags |= flag;/* setup timeout if no clockevent */ -if ((flag ==FLAG_CLOCKSOURCE ) && (!(p->flags &FLAG_CLOCKEVENT ))) -__sh_cmt_set_next (p, p->max_match_value); +if ((flag ==FLAG_CLOCKSOURCE ) && (!(ch->flags &FLAG_CLOCKEVENT ))) +__sh_cmt_set_next (ch, ch->max_match_value); out: -raw_spin_unlock_irqrestore (&p->lock, flags); +raw_spin_unlock_irqrestore (&ch->lock, flags);return ret; } -static void sh_cmt_stop (struct sh_cmt_priv *p,unsigned long flag) +static void sh_cmt_stop (struct sh_cmt_channel *ch,unsigned long flag) {unsigned long flags;unsigned long f; -raw_spin_lock_irqsave (&p->lock, flags); +raw_spin_lock_irqsave (&ch->lock, flags); - f = p->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ); - p->flags &= ~flag; + f = ch->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ); + ch->flags &= ~flag; -if (f && !(p->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ))) -sh_cmt_disable (p); +if (f && !(ch->flags & (FLAG_CLOCKEVENT |FLAG_CLOCKSOURCE ))) +sh_cmt_disable (ch);/* adjust the timeout to maximum if only clocksource left */ -if ((flag ==FLAG_CLOCKEVENT ) && (p->flags &FLAG_CLOCKSOURCE )) -__sh_cmt_set_next (p, p->max_match_value); +if ((flag ==FLAG_CLOCKEVENT ) && (ch->flags &FLAG_CLOCKSOURCE )) +__sh_cmt_set_next (ch, ch->max_match_value); -raw_spin_unlock_irqrestore (&p->lock, flags); +raw_spin_unlock_irqrestore (&ch->lock, flags); } -static struct sh_cmt_priv *cs_to_sh_cmt (struct clocksource *cs) +static struct sh_cmt_channel *cs_to_sh_cmt (struct clocksource *cs) { - return container_of(cs, struct sh_cmt_priv, cs); + return container_of(cs, struct sh_cmt_channel, cs); }static cycle_t sh_cmt_clocksource_read (struct clocksource *cs) { -struct sh_cmt_priv *p =cs_to_sh_cmt (cs); +struct sh_cmt_channel *ch =cs_to_sh_cmt (cs);unsigned long flags, raw;unsigned long value;int has_wrapped; -raw_spin_lock_irqsave (&p->lock, flags); - value = p->total_cycles; - raw =sh_cmt_get_counter (p, &has_wrapped); +raw_spin_lock_irqsave (&ch->lock, flags); + value = ch->total_cycles; + raw =sh_cmt_get_counter (ch, &has_wrapped);if (unlikely (has_wrapped)) - raw += p->match_value +1 ; -raw_spin_unlock_irqrestore (&p->lock, flags); + raw += ch->match_value +1 ; +raw_spin_unlock_irqrestore (&ch->lock, flags);return value + raw; }
@@ -499,50 +508,50 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)static int sh_cmt_clocksource_enable (struct clocksource *cs) {int ret; -struct sh_cmt_priv *p =cs_to_sh_cmt (cs); +struct sh_cmt_channel *ch =cs_to_sh_cmt (cs); -WARN_ON (p->cs_enabled); +WARN_ON (ch->cs_enabled); - p->total_cycles =0 ; + ch->total_cycles =0 ; - ret =sh_cmt_start (p,FLAG_CLOCKSOURCE ); + ret =sh_cmt_start (ch,FLAG_CLOCKSOURCE );if (!ret) { -__clocksource_updatefreq_hz (cs, p->rate); - p->cs_enabled = true; +__clocksource_updatefreq_hz (cs, ch->rate); + ch->cs_enabled = true; }return ret; }static void sh_cmt_clocksource_disable (struct clocksource *cs) { -struct sh_cmt_priv *p =cs_to_sh_cmt (cs); +struct sh_cmt_channel *ch =cs_to_sh_cmt (cs); -WARN_ON (!p->cs_enabled); +WARN_ON (!ch->cs_enabled); -sh_cmt_stop (p,FLAG_CLOCKSOURCE ); - p->cs_enabled = false; +sh_cmt_stop (ch,FLAG_CLOCKSOURCE ); + ch->cs_enabled = false; }static void sh_cmt_clocksource_suspend (struct clocksource *cs) { -struct sh_cmt_priv *p =cs_to_sh_cmt (cs); +struct sh_cmt_channel *ch =cs_to_sh_cmt (cs); -sh_cmt_stop (p,FLAG_CLOCKSOURCE ); -pm_genpd_syscore_poweroff (&p->pdev->dev); +sh_cmt_stop (ch,FLAG_CLOCKSOURCE ); +pm_genpd_syscore_poweroff (&ch->cmt->pdev->dev); }static void sh_cmt_clocksource_resume (struct clocksource *cs) { -struct sh_cmt_priv *p =cs_to_sh_cmt (cs); +struct sh_cmt_channel *ch =cs_to_sh_cmt (cs); -pm_genpd_syscore_poweron (&p->pdev->dev); -sh_cmt_start (p,FLAG_CLOCKSOURCE ); +pm_genpd_syscore_poweron (&ch->cmt->pdev->dev); +sh_cmt_start (ch,FLAG_CLOCKSOURCE ); } -static int sh_cmt_register_clocksource (struct sh_cmt_priv *p, +static int sh_cmt_register_clocksource (struct sh_cmt_channel *ch,char *name,unsigned long rating) { -struct clocksource *cs = &p->cs; +struct clocksource *cs = &ch->cs; cs->name = name; cs->rating = rating;
@@ -554,47 +563,47 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, cs->mask =CLOCKSOURCE_MASK (sizeof (unsigned long ) *8 ); cs->flags =CLOCK_SOURCE_IS_CONTINUOUS ; -dev_info (&p->pdev->dev,"used as clock source\n" ); +dev_info (&ch->cmt->pdev->dev,"used as clock source\n" );/* Register with dummy 1 Hz value, gets updated in ->enable() */ clocksource_register_hz (cs,1 );return 0 ; } -static struct sh_cmt_priv *ced_to_sh_cmt (struct clock_event_device *ced) +static struct sh_cmt_channel *ced_to_sh_cmt (struct clock_event_device *ced) { - return container_of(ced, struct sh_cmt_priv, ced); + return container_of(ced, struct sh_cmt_channel, ced); } -static void sh_cmt_clock_event_start (struct sh_cmt_priv *p,int periodic) +static void sh_cmt_clock_event_start (struct sh_cmt_channel *ch,int periodic) { -struct clock_event_device *ced = &p->ced; +struct clock_event_device *ced = &ch->ced; -sh_cmt_start (p,FLAG_CLOCKEVENT ); +sh_cmt_start (ch,FLAG_CLOCKEVENT );/* TODO: calculate good shift from rate and counter bit width */ ced->shift =32 ; - ced->mult =div_sc (p->rate,NSEC_PER_SEC , ced->shift); - ced->max_delta_ns =clockevent_delta2ns (p->max_match_value, ced); + ced->mult =div_sc (ch->rate,NSEC_PER_SEC , ced->shift); + ced->max_delta_ns =clockevent_delta2ns (ch->max_match_value, ced); ced->min_delta_ns =clockevent_delta2ns (0x1f , ced);if (periodic) -sh_cmt_set_next (p, ((p->rate +HZ /2 ) /HZ ) -1 ); +sh_cmt_set_next (ch, ((ch->rate +HZ /2 ) /HZ ) -1 );else -sh_cmt_set_next (p, p->max_match_value); +sh_cmt_set_next (ch, ch->max_match_value); }static void sh_cmt_clock_event_mode (enum clock_event_mode mode,struct clock_event_device *ced) { -struct sh_cmt_priv *p =ced_to_sh_cmt (ced); +struct sh_cmt_channel *ch =ced_to_sh_cmt (ced);/* deal with old setting first */ switch (ced->mode) {case CLOCK_EVT_MODE_PERIODIC :case CLOCK_EVT_MODE_ONESHOT : -sh_cmt_stop (p,FLAG_CLOCKEVENT ); +sh_cmt_stop (ch,FLAG_CLOCKEVENT );break ;default :break ;
@@ -602,16 +611,18 @@ static void sh_cmt_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC : -dev_info (&p->pdev->dev,"used for periodic clock events\n" ); -sh_cmt_clock_event_start (p,1 ); +dev_info (&ch->cmt->pdev->dev, +"used for periodic clock events\n" ); +sh_cmt_clock_event_start (ch,1 );break ;case CLOCK_EVT_MODE_ONESHOT : -dev_info (&p->pdev->dev,"used for oneshot clock events\n" ); -sh_cmt_clock_event_start (p,0 ); +dev_info (&ch->cmt->pdev->dev, +"used for oneshot clock events\n" ); +sh_cmt_clock_event_start (ch,0 );break ;case CLOCK_EVT_MODE_SHUTDOWN :case CLOCK_EVT_MODE_UNUSED : -sh_cmt_stop (p,FLAG_CLOCKEVENT ); +sh_cmt_stop (ch,FLAG_CLOCKEVENT );break ;default :break ;
@@ -621,37 +632,37 @@ static void sh_cmt_clock_event_mode(enum clock_event_mode mode,static int sh_cmt_clock_event_next (unsigned long delta,struct clock_event_device *ced) { -struct sh_cmt_priv *p =ced_to_sh_cmt (ced); +struct sh_cmt_channel *ch =ced_to_sh_cmt (ced);BUG_ON (ced->mode !=CLOCK_EVT_MODE_ONESHOT ); -if (likely (p->flags &FLAG_IRQCONTEXT )) - p->next_match_value = delta -1 ; +if (likely (ch->flags &FLAG_IRQCONTEXT )) + ch->next_match_value = delta -1 ;else -sh_cmt_set_next (p, delta -1 ); +sh_cmt_set_next (ch, delta -1 );return 0 ; }static void sh_cmt_clock_event_suspend (struct clock_event_device *ced) { -struct sh_cmt_priv *p =ced_to_sh_cmt (ced); +struct sh_cmt_channel *ch =ced_to_sh_cmt (ced); -pm_genpd_syscore_poweroff (&p->pdev->dev); -clk_unprepare (p->clk); +pm_genpd_syscore_poweroff (&ch->cmt->pdev->dev); +clk_unprepare (ch->cmt->clk); }static void sh_cmt_clock_event_resume (struct clock_event_device *ced) { -struct sh_cmt_priv *p =ced_to_sh_cmt (ced); +struct sh_cmt_channel *ch =ced_to_sh_cmt (ced); -clk_prepare (p->clk); -pm_genpd_syscore_poweron (&p->pdev->dev); +clk_prepare (ch->cmt->clk); +pm_genpd_syscore_poweron (&ch->cmt->pdev->dev); } -static void sh_cmt_register_clockevent (struct sh_cmt_priv *p, +static void sh_cmt_register_clockevent (struct sh_cmt_channel *ch,char *name,unsigned long rating) { -struct clock_event_device *ced = &p->ced; +struct clock_event_device *ced = &ch->ced;memset (ced,0 ,sizeof (*ced));
@@ -665,19 +676,19 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, ced->suspend = sh_cmt_clock_event_suspend; ced->resume = sh_cmt_clock_event_resume; -dev_info (&p->pdev->dev,"used for clock events\n" ); +dev_info (&ch->cmt->pdev->dev,"used for clock events\n" );clockevents_register_device (ced); } -static int sh_cmt_register (struct sh_cmt_priv *p,char *name, +static int sh_cmt_register (struct sh_cmt_channel *ch,char *name,unsigned long clockevent_rating,unsigned long clocksource_rating) {if (clockevent_rating) -sh_cmt_register_clockevent (p, name, clockevent_rating); +sh_cmt_register_clockevent (ch, name, clockevent_rating);if (clocksource_rating) -sh_cmt_register_clocksource (p, name, clocksource_rating); +sh_cmt_register_clocksource (ch, name, clocksource_rating);return 0 ; }
@@ -685,6 +696,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name,static int sh_cmt_setup (struct sh_cmt_priv *p,struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data; +struct sh_cmt_channel *ch = &p->channel;struct resource *res, *res2;int irq, ret; ret = -ENXIO ;
@@ -763,26 +775,27 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) p->clear_bits = ~0xc000 ; } -if (p->width == (sizeof (p->max_match_value) *8 )) - p->max_match_value = ~0 ; +if (p->width == (sizeof (ch->max_match_value) *8 )) + ch->max_match_value = ~0 ;else - p->max_match_value = (1 << p->width) -1 ; + ch->max_match_value = (1 << p->width) -1 ; - p->match_value = p->max_match_value; -raw_spin_lock_init (&p->lock); + ch->cmt = p; + ch->match_value = ch->max_match_value; +raw_spin_lock_init (&ch->lock); - ret =sh_cmt_register (p, (char *)dev_name (&p->pdev->dev), + ret =sh_cmt_register (ch, (char *)dev_name (&p->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating);if (ret) {dev_err (&p->pdev->dev,"registration failed\n" ); goto err4; } - p->cs_enabled = false; + ch->cs_enabled = false; ret =request_irq (irq, sh_cmt_interrupt,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&p->pdev->dev), p); +dev_name (&p->pdev->dev), ch);if (ret) {dev_err (&p->pdev->dev,"failed to request irq %d\n" , irq); goto err4;
Signature · 1 line
1.7.9.5
PATCH 3/71 clocksource: sh_cmt: Rename struct sh_cmt_priv to sh_cmt_device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Channel data is private as well, rename priv to device to make the distrinction between the core device and the channels clearer.
--- drivers/clocksource/sh_cmt.c | 116 +++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 58 deletions(-)
drivers/clocksource/sh_cmt.c +58 -58
@@ -35,10 +35,10 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> -struct sh_cmt_priv ; +struct sh_cmt_device ;struct sh_cmt_channel { -struct sh_cmt_priv *cmt; +struct sh_cmt_device *cmt;unsigned long flags;unsigned long match_value;
@@ -52,7 +52,7 @@ struct sh_cmt_channel {bool cs_enabled; }; -struct sh_cmt_priv { +struct sh_cmt_device {struct platform_device *pdev;void __iomem *mapbase;
@@ -693,132 +693,132 @@ static int sh_cmt_register(struct sh_cmt_channel *ch, char *name,return 0 ; } -static int sh_cmt_setup (struct sh_cmt_priv *p,struct platform_device *pdev) +static int sh_cmt_setup (struct sh_cmt_device *cmt,struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data; -struct sh_cmt_channel *ch = &p->channel; +struct sh_cmt_channel *ch = &cmt->channel;struct resource *res, *res2;int irq, ret; ret = -ENXIO ; -memset (p,0 ,sizeof (*p)); - p->pdev = pdev; +memset (cmt,0 ,sizeof (*cmt)); + cmt->pdev = pdev;if (!cfg) { -dev_err (&p->pdev->dev,"missing platform data\n" ); +dev_err (&cmt->pdev->dev,"missing platform data\n" ); goto err0; } - res =platform_get_resource (p->pdev,IORESOURCE_MEM ,0 ); + res =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,0 );if (!res) { -dev_err (&p->pdev->dev,"failed to get I/O memory\n" ); +dev_err (&cmt->pdev->dev,"failed to get I/O memory\n" ); goto err0; }/* optional resource for the shared timer start/stop register */ - res2 =platform_get_resource (p->pdev,IORESOURCE_MEM ,1 ); + res2 =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,1 ); - irq =platform_get_irq (p->pdev,0 ); + irq =platform_get_irq (cmt->pdev,0 );if (irq <0 ) { -dev_err (&p->pdev->dev,"failed to get irq\n" ); +dev_err (&cmt->pdev->dev,"failed to get irq\n" ); goto err0; }/* map memory, let mapbase point to our channel */ - p->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (p->mapbase ==NULL ) { -dev_err (&p->pdev->dev,"failed to remap I/O memory\n" ); + cmt->mapbase =ioremap_nocache (res->start,resource_size (res)); +if (cmt->mapbase ==NULL ) { +dev_err (&cmt->pdev->dev,"failed to remap I/O memory\n" ); goto err0; }/* map second resource for CMSTR */ - p->mapbase_str =ioremap_nocache (res2 ? res2->start : - res->start - cfg->channel_offset, - res2 ?resource_size (res2) :2 ); -if (p->mapbase_str ==NULL ) { -dev_err (&p->pdev->dev,"failed to remap I/O second memory\n" ); + cmt->mapbase_str =ioremap_nocache (res2 ? res2->start : + res->start - cfg->channel_offset, + res2 ?resource_size (res2) :2 ); +if (cmt->mapbase_str ==NULL ) { +dev_err (&cmt->pdev->dev,"failed to remap I/O second memory\n" ); goto err1; }/* get hold of clock */ - p->clk =clk_get (&p->pdev->dev,"cmt_fck" ); -if (IS_ERR (p->clk)) { -dev_err (&p->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (p->clk); + cmt->clk =clk_get (&cmt->pdev->dev,"cmt_fck" ); +if (IS_ERR (cmt->clk)) { +dev_err (&cmt->pdev->dev,"cannot get clock\n" ); + ret =PTR_ERR (cmt->clk); goto err2; } - ret =clk_prepare (p->clk); + ret =clk_prepare (cmt->clk);if (ret <0 ) goto err3;if (res2 && (resource_size (res2) ==4 )) {/* assume both CMSTR and CMCSR to be 32-bit */ - p->read_control = sh_cmt_read32; - p->write_control = sh_cmt_write32; + cmt->read_control = sh_cmt_read32; + cmt->write_control = sh_cmt_write32; }else { - p->read_control = sh_cmt_read16; - p->write_control = sh_cmt_write16; + cmt->read_control = sh_cmt_read16; + cmt->write_control = sh_cmt_write16; }if (resource_size (res) ==6 ) { - p->width =16 ; - p->read_count = sh_cmt_read16; - p->write_count = sh_cmt_write16; - p->overflow_bit =0x80 ; - p->clear_bits = ~0x80 ; + cmt->width =16 ; + cmt->read_count = sh_cmt_read16; + cmt->write_count = sh_cmt_write16; + cmt->overflow_bit =0x80 ; + cmt->clear_bits = ~0x80 ; }else { - p->width =32 ; - p->read_count = sh_cmt_read32; - p->write_count = sh_cmt_write32; - p->overflow_bit =0x8000 ; - p->clear_bits = ~0xc000 ; + cmt->width =32 ; + cmt->read_count = sh_cmt_read32; + cmt->write_count = sh_cmt_write32; + cmt->overflow_bit =0x8000 ; + cmt->clear_bits = ~0xc000 ; } -if (p->width == (sizeof (ch->max_match_value) *8 )) +if (cmt->width == (sizeof (ch->max_match_value) *8 )) ch->max_match_value = ~0 ;else - ch->max_match_value = (1 << p->width) -1 ; + ch->max_match_value = (1 << cmt->width) -1 ; - ch->cmt = p; + ch->cmt = cmt; ch->match_value = ch->max_match_value;raw_spin_lock_init (&ch->lock); - ret =sh_cmt_register (ch, (char *)dev_name (&p->pdev->dev), + ret =sh_cmt_register (ch, (char *)dev_name (&cmt->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating);if (ret) { -dev_err (&p->pdev->dev,"registration failed\n" ); +dev_err (&cmt->pdev->dev,"registration failed\n" ); goto err4; } ch->cs_enabled = false; ret =request_irq (irq, sh_cmt_interrupt,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&p->pdev->dev), ch); +dev_name (&cmt->pdev->dev), ch);if (ret) { -dev_err (&p->pdev->dev,"failed to request irq %d\n" , irq); +dev_err (&cmt->pdev->dev,"failed to request irq %d\n" , irq); goto err4; } -platform_set_drvdata (pdev, p); +platform_set_drvdata (pdev, cmt);return 0 ; err4: -clk_unprepare (p->clk); +clk_unprepare (cmt->clk); err3: -clk_put (p->clk); +clk_put (cmt->clk); err2: -iounmap (p->mapbase_str); +iounmap (cmt->mapbase_str); err1: -iounmap (p->mapbase); +iounmap (cmt->mapbase); err0:return ret; }static int sh_cmt_probe (struct platform_device *pdev) { -struct sh_cmt_priv *p =platform_get_drvdata (pdev); +struct sh_cmt_device *cmt =platform_get_drvdata (pdev);struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;
@@ -827,20 +827,20 @@ static int sh_cmt_probe(struct platform_device *pdev)pm_runtime_enable (&pdev->dev); } -if (p) { +if (cmt) {dev_info (&pdev->dev,"kept as earlytimer\n" ); goto out; } - p =kmalloc (sizeof (*p),GFP_KERNEL ); -if (p ==NULL ) { + cmt =kmalloc (sizeof (*cmt),GFP_KERNEL ); +if (cmt ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ; } - ret =sh_cmt_setup (p, pdev); + ret =sh_cmt_setup (cmt, pdev);if (ret) { -kfree (p); +kfree (cmt);pm_runtime_idle (&pdev->dev);return ret; }
Signature · 1 line
1.7.9.5
PATCH 4/71 clocksource: sh_cmt: Split channel setup to separate function
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Move the channel setup code from sh_cmt_setup to a new sh_cmt_setup_channel function and call it from sh_cmt_setup.
--- drivers/clocksource/sh_cmt.c | 79 +++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 32 deletions(-)
drivers/clocksource/sh_cmt.c +47 -32
@@ -693,12 +693,55 @@ static int sh_cmt_register(struct sh_cmt_channel *ch, char *name,return 0 ; } +static int sh_cmt_setup_channel (struct sh_cmt_channel *ch, +struct sh_cmt_device *cmt) +{ +struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; +int irq; +int ret; + +memset (ch,0 ,sizeof (*ch)); + ch->cmt = cmt; + + irq =platform_get_irq (cmt->pdev,0 ); +if (irq <0 ) { +dev_err (&cmt->pdev->dev,"failed to get irq\n" ); +return irq; + } + +if (cmt->width == (sizeof (ch->max_match_value) *8 )) + ch->max_match_value = ~0 ; +else + ch->max_match_value = (1 << cmt->width) -1 ; + + ch->match_value = ch->max_match_value; +raw_spin_lock_init (&ch->lock); + + ret =sh_cmt_register (ch, (char *)dev_name (&cmt->pdev->dev), + cfg->clockevent_rating, + cfg->clocksource_rating); +if (ret) { +dev_err (&cmt->pdev->dev,"registration failed\n" ); +return ret; + } + ch->cs_enabled = false; + + ret =request_irq (irq, sh_cmt_interrupt, +IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , +dev_name (&cmt->pdev->dev), ch); +if (ret) { +dev_err (&cmt->pdev->dev,"failed to request irq %d\n" , irq); +return ret; + } + +return 0 ; +} +static int sh_cmt_setup (struct sh_cmt_device *cmt,struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data; -struct sh_cmt_channel *ch = &cmt->channel;struct resource *res, *res2; -int irq, ret; +int ret; ret = -ENXIO ;memset (cmt,0 ,sizeof (*cmt));
@@ -718,12 +761,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)/* optional resource for the shared timer start/stop register */ res2 =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,1 ); - irq =platform_get_irq (cmt->pdev,0 ); -if (irq <0 ) { -dev_err (&cmt->pdev->dev,"failed to get irq\n" ); - goto err0; - } -/* map memory, let mapbase point to our channel */ cmt->mapbase =ioremap_nocache (res->start,resource_size (res));if (cmt->mapbase ==NULL ) {
@@ -775,31 +812,9 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) cmt->clear_bits = ~0xc000 ; } -if (cmt->width == (sizeof (ch->max_match_value) *8 )) - ch->max_match_value = ~0 ; -else - ch->max_match_value = (1 << cmt->width) -1 ; - - ch->cmt = cmt; - ch->match_value = ch->max_match_value; -raw_spin_lock_init (&ch->lock); - - ret =sh_cmt_register (ch, (char *)dev_name (&cmt->pdev->dev), - cfg->clockevent_rating, - cfg->clocksource_rating); -if (ret) { -dev_err (&cmt->pdev->dev,"registration failed\n" ); - goto err4; - } - ch->cs_enabled = false; - - ret =request_irq (irq, sh_cmt_interrupt, -IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&cmt->pdev->dev), ch); -if (ret) { -dev_err (&cmt->pdev->dev,"failed to request irq %d\n" , irq); + ret =sh_cmt_setup_channel (&cmt->channel, cmt); +if (ret <0 ) goto err4; - }platform_set_drvdata (pdev, cmt);
Signature · 1 line
1.7.9.5
PATCH 5/71 clocksource: sh_cmt: Constify name argument to sh_cmt_register()
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The name argument is assigned to const structure fields only, constify it.
--- drivers/clocksource/sh_cmt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/clocksource/sh_cmt.c +4 -4
@@ -549,7 +549,7 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs) }static int sh_cmt_register_clocksource (struct sh_cmt_channel *ch, -char *name,unsigned long rating) +const char *name,unsigned long rating) {struct clocksource *cs = &ch->cs;
@@ -660,7 +660,7 @@ static void sh_cmt_clock_event_resume(struct clock_event_device *ced) }static void sh_cmt_register_clockevent (struct sh_cmt_channel *ch, -char *name,unsigned long rating) +const char *name,unsigned long rating) {struct clock_event_device *ced = &ch->ced;
@@ -680,7 +680,7 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,clockevents_register_device (ced); } -static int sh_cmt_register (struct sh_cmt_channel *ch,char *name, +static int sh_cmt_register (struct sh_cmt_channel *ch,const char *name,unsigned long clockevent_rating,unsigned long clocksource_rating) {
@@ -717,7 +717,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, ch->match_value = ch->max_match_value;raw_spin_lock_init (&ch->lock); - ret =sh_cmt_register (ch, (char *)dev_name (&cmt->pdev->dev), + ret =sh_cmt_register (ch,dev_name (&cmt->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating);if (ret) {
Signature · 1 line
1.7.9.5
PATCH 6/71 clocksource: sh_cmt: Rename mapbase/mapbase_str to mapbase_ch/mapbase
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The mapbase variable points to the mapped base address of the channel, rename it to mapbase_sh. mapbase_str points to the mapped base address of the CMT device, rename it to mapbase.
--- drivers/clocksource/sh_cmt.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-)
drivers/clocksource/sh_cmt.c +17 -17
@@ -55,8 +55,8 @@ struct sh_cmt_channel {struct sh_cmt_device {struct platform_device *pdev; +void __iomem *mapbase_ch;void __iomem *mapbase; -void __iomem *mapbase_str;struct clk *clk;struct sh_cmt_channel channel;
@@ -125,41 +125,41 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,static inline unsigned long sh_cmt_read_cmstr (struct sh_cmt_channel *ch) { -return ch->cmt->read_control (ch->cmt->mapbase_str,0 ); +return ch->cmt->read_control (ch->cmt->mapbase,0 ); }static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) { -return ch->cmt->read_control (ch->cmt->mapbase,CMCSR ); +return ch->cmt->read_control (ch->cmt->mapbase_ch,CMCSR ); }static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) { -return ch->cmt->read_count (ch->cmt->mapbase,CMCNT ); +return ch->cmt->read_count (ch->cmt->mapbase_ch,CMCNT ); }static inline void sh_cmt_write_cmstr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_control (ch->cmt->mapbase_str,0 , value); + ch->cmt->write_control (ch->cmt->mapbase,0 , value); }static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_control (ch->cmt->mapbase,CMCSR , value); + ch->cmt->write_control (ch->cmt->mapbase_ch,CMCSR , value); }static inline void sh_cmt_write_cmcnt (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->cmt->mapbase,CMCNT , value); + ch->cmt->write_count (ch->cmt->mapbase_ch,CMCNT , value); }static inline void sh_cmt_write_cmcor (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->cmt->mapbase,CMCOR , value); + ch->cmt->write_count (ch->cmt->mapbase_ch,CMCOR , value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
@@ -761,18 +761,18 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)/* optional resource for the shared timer start/stop register */ res2 =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,1 ); -/* map memory, let mapbase point to our channel */ - cmt->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (cmt->mapbase ==NULL ) { +/* map memory, let mapbase_ch point to our channel */ + cmt->mapbase_ch =ioremap_nocache (res->start,resource_size (res)); +if (cmt->mapbase_ch ==NULL ) {dev_err (&cmt->pdev->dev,"failed to remap I/O memory\n" ); goto err0; }/* map second resource for CMSTR */ - cmt->mapbase_str =ioremap_nocache (res2 ? res2->start : - res->start - cfg->channel_offset, - res2 ?resource_size (res2) :2 ); -if (cmt->mapbase_str ==NULL ) { + cmt->mapbase =ioremap_nocache (res2 ? res2->start : + res->start - cfg->channel_offset, + res2 ?resource_size (res2) :2 ); +if (cmt->mapbase ==NULL ) {dev_err (&cmt->pdev->dev,"failed to remap I/O second memory\n" ); goto err1; }
@@ -824,9 +824,9 @@ err4: err3:clk_put (cmt->clk); err2: -iounmap (cmt->mapbase_str); -err1:iounmap (cmt->mapbase); +err1: +iounmap (cmt->mapbase_ch); err0:return ret; }
Signature · 1 line
1.7.9.5
PATCH 7/71 clocksource: sh_cmt: Add memory base to sh_cmt_channel structure
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The channel memory base is channel-specific, add it to the channel structure in preparation for support of multiple channels per device.
--- drivers/clocksource/sh_cmt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/clocksource/sh_cmt.c +8 -5
@@ -40,6 +40,8 @@ struct sh_cmt_device;struct sh_cmt_channel {struct sh_cmt_device *cmt; +void __iomem *base; +unsigned long flags;unsigned long match_value;unsigned long next_match_value;
@@ -130,12 +132,12 @@ static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) { -return ch->cmt->read_control (ch->cmt->mapbase_ch,CMCSR ); +return ch->cmt->read_control (ch->base,CMCSR ); }static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) { -return ch->cmt->read_count (ch->cmt->mapbase_ch,CMCNT ); +return ch->cmt->read_count (ch->base,CMCNT ); } static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
@@ -147,19 +149,19 @@ static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_control (ch->cmt->mapbase_ch,CMCSR , value); + ch->cmt->write_control (ch->base,CMCSR , value); }static inline void sh_cmt_write_cmcnt (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->cmt->mapbase_ch,CMCNT , value); + ch->cmt->write_count (ch->base,CMCNT , value); }static inline void sh_cmt_write_cmcor (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->cmt->mapbase_ch,CMCOR , value); + ch->cmt->write_count (ch->base,CMCOR , value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
@@ -702,6 +704,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch,memset (ch,0 ,sizeof (*ch)); ch->cmt = cmt; + ch->base = cmt->mapbase_ch; irq =platform_get_irq (cmt->pdev,0 );if (irq <0 ) {
Signature · 1 line
1.7.9.5
PATCH 8/71 clocksource: sh_cmt: Add index to struct sh_cmt_channel
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Use the index when printing messages to identify the channel.
--- drivers/clocksource/sh_cmt.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-)
drivers/clocksource/sh_cmt.c +24 -13
@@ -39,6 +39,7 @@ struct sh_cmt_device;struct sh_cmt_channel {struct sh_cmt_device *cmt; +unsigned int index;void __iomem *base;
@@ -216,7 +217,8 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)/* enable clock */ ret =clk_enable (ch->cmt->clk);if (ret) { -dev_err (&ch->cmt->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->cmt->pdev->dev,"ch%u: cannot enable clock\n" , + ch->index); goto err0; }
@@ -253,7 +255,8 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate) }if (sh_cmt_read_cmcnt (ch)) { -dev_err (&ch->cmt->pdev->dev,"cannot clear CMCNT\n" ); +dev_err (&ch->cmt->pdev->dev,"ch%u: cannot clear CMCNT\n" , + ch->index); ret = -ETIMEDOUT ; goto err1; }
@@ -371,7 +374,8 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch, delay =1 ;if (!delay) -dev_warn (&ch->cmt->pdev->dev,"too long delay\n" ); +dev_warn (&ch->cmt->pdev->dev,"ch%u: too long delay\n" , + ch->index); }while (delay); }
@@ -379,7 +383,8 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,static void __sh_cmt_set_next (struct sh_cmt_channel *ch,unsigned long delta) {if (delta > ch->max_match_value) -dev_warn (&ch->cmt->pdev->dev,"delta out of range\n" ); +dev_warn (&ch->cmt->pdev->dev,"ch%u: delta out of range\n" , + ch->index); ch->next_match_value = delta;sh_cmt_clock_event_program_verify (ch,0 );
@@ -565,7 +570,8 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch, cs->mask =CLOCKSOURCE_MASK (sizeof (unsigned long ) *8 ); cs->flags =CLOCK_SOURCE_IS_CONTINUOUS ; -dev_info (&ch->cmt->pdev->dev,"used as clock source\n" ); +dev_info (&ch->cmt->pdev->dev,"ch%u: used as clock source\n" , + ch->index);/* Register with dummy 1 Hz value, gets updated in ->enable() */ clocksource_register_hz (cs,1 );
@@ -614,12 +620,12 @@ static void sh_cmt_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC :dev_info (&ch->cmt->pdev->dev, -"used for periodic clock events\n" ); +"ch%u: used for periodic clock events\n" , ch->index);sh_cmt_clock_event_start (ch,1 );break ;case CLOCK_EVT_MODE_ONESHOT :dev_info (&ch->cmt->pdev->dev, -"used for oneshot clock events\n" ); +"ch%u: used for oneshot clock events\n" , ch->index);sh_cmt_clock_event_start (ch,0 );break ;case CLOCK_EVT_MODE_SHUTDOWN :
@@ -678,7 +684,8 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, ced->suspend = sh_cmt_clock_event_suspend; ced->resume = sh_cmt_clock_event_resume; -dev_info (&ch->cmt->pdev->dev,"used for clock events\n" ); +dev_info (&ch->cmt->pdev->dev,"ch%u: used for clock events\n" , + ch->index);clockevents_register_device (ced); }
@@ -695,7 +702,7 @@ static int sh_cmt_register(struct sh_cmt_channel *ch, const char *name,return 0 ; } -static int sh_cmt_setup_channel (struct sh_cmt_channel *ch, +static int sh_cmt_setup_channel (struct sh_cmt_channel *ch,unsigned int index,struct sh_cmt_device *cmt) {struct sh_timer_config *cfg = cmt->pdev->dev.platform_data;
@@ -705,10 +712,12 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch,memset (ch,0 ,sizeof (*ch)); ch->cmt = cmt; ch->base = cmt->mapbase_ch; + ch->index = index; irq =platform_get_irq (cmt->pdev,0 );if (irq <0 ) { -dev_err (&cmt->pdev->dev,"failed to get irq\n" ); +dev_err (&cmt->pdev->dev,"ch%u: failed to get irq\n" , + ch->index);return irq; }
@@ -724,7 +733,8 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, cfg->clockevent_rating, cfg->clocksource_rating);if (ret) { -dev_err (&cmt->pdev->dev,"registration failed\n" ); +dev_err (&cmt->pdev->dev,"ch%u: registration failed\n" , + ch->index);return ret; } ch->cs_enabled = false;
@@ -733,7 +743,8 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , dev_name(&cmt->pdev->dev), ch);if (ret) { -dev_err (&cmt->pdev->dev,"failed to request irq %d\n" , irq); +dev_err (&cmt->pdev->dev,"ch%u: failed to request irq %d\n" , + ch->index, irq);return ret; }
@@ -815,7 +826,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) cmt->clear_bits = ~0xc000 ; } - ret =sh_cmt_setup_channel (&cmt->channel, cmt); + ret =sh_cmt_setup_channel (&cmt->channel, cfg->timer_bit, cmt);if (ret <0 ) goto err4;
Signature · 1 line
1.7.9.5
PATCH 9/71 clocksource: sh_cmt: Replace kmalloc + memset with kzalloc
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
One kzalloc a day keeps the bugs away.
--- drivers/clocksource/sh_cmt.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/clocksource/sh_cmt.c +1 -5
@@ -672,8 +672,6 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, {struct clock_event_device *ced = &ch->ced; -memset (ced,0 ,sizeof (*ced)); - ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->features |=CLOCK_EVT_FEAT_ONESHOT ;
@@ -709,7 +707,6 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,int irq;int ret; -memset (ch,0 ,sizeof (*ch)); ch->cmt = cmt; ch->base = cmt->mapbase_ch; ch->index = index;
@@ -758,7 +755,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)int ret; ret = -ENXIO ; -memset (cmt,0 ,sizeof (*cmt)); cmt->pdev = pdev;if (!cfg) {
@@ -861,7 +857,7 @@ static int sh_cmt_probe(struct platform_device *pdev) goto out; } - cmt =kmalloc (sizeof (*cmt),GFP_KERNEL ); + cmt =kzalloc (sizeof (*cmt),GFP_KERNEL );if (cmt ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ;
Signature · 1 line
1.7.9.5
PATCH 10/71 clocksource: sh_cmt: Allocate channels dynamically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This prepares the driver for multi-channel support.
--- drivers/clocksource/sh_cmt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/clocksource/sh_cmt.c +12 -2
@@ -62,7 +62,8 @@ struct sh_cmt_device {void __iomem *mapbase;struct clk *clk; -struct sh_cmt_channel channel; +struct sh_cmt_channel *channels; +unsigned int num_channels;unsigned long width;/* 16 or 32 bit version of hardware block */ unsigned long overflow_bit;
@@ -822,7 +823,15 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) cmt->clear_bits = ~0xc000 ; } - ret =sh_cmt_setup_channel (&cmt->channel, cfg->timer_bit, cmt); + cmt->channels =kzalloc (sizeof (*cmt->channels),GFP_KERNEL ); +if (cmt->channels ==NULL ) { + ret = -ENOMEM ; + goto err4; + } + + cmt->num_channels =1 ; + + ret =sh_cmt_setup_channel (&cmt->channels[0 ], cfg->timer_bit, cmt);if (ret <0 ) goto err4;
@@ -830,6 +839,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)return 0 ; err4: +kfree (cmt->channels);clk_unprepare (cmt->clk); err3:clk_put (cmt->clk);
Signature · 1 line
1.7.9.5
PATCH 11/71 clocksource: sh_cmt: Split static information from sh_cmt_device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Create a new sh_cmt_info structure to hold static information about the device model and reference that structure from the sh_cmt_device structure.
--- drivers/clocksource/sh_cmt.c | 192 +++++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 70 deletions(-)
drivers/clocksource/sh_cmt.c +122 -70
@@ -37,6 +37,52 @@struct sh_cmt_device ; +/* +* The CMT comes in 5 different identified flavours, depending not only on the +* SoC but also on the particular instance. The following table lists the main +* characteristics of those flavours. +* +* 16B 32B 32B-F 48B 48B-2 +* ----------------------------------------------------------------------------- +* Channels 2 1/4 1 6 2/8 +* Control Width 16 16 16 16 32 +* Counter Width 16 32 32 32/48 32/48 +* Shared Start/Stop Y Y Y Y N +* +* The 48-bit gen2 version has a per-channel start/stop register located in the +* channel registers block. All other versions have a shared start/stop register +* located in the global space. +* +* Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit +* channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable. +*/ + +enum sh_cmt_model { +SH_CMT_16BIT , +SH_CMT_32BIT , +SH_CMT_32BIT_FAST , +SH_CMT_48BIT , +SH_CMT_48BIT_GEN2 , +}; + +struct sh_cmt_info { +enum sh_cmt_model model; + +unsigned long width;/* 16 or 32 bit version of hardware block */ +unsigned long overflow_bit; +unsigned long clear_bits; + +/* callbacks for CMSTR and CMCSR access */ +unsigned long (*read_control)(void __iomem *base,unsigned long offs); +void (*write_control)(void __iomem *base,unsigned long offs, +unsigned long value); + +/* callbacks for CMCNT and CMCOR access */ +unsigned long (*read_count)(void __iomem *base,unsigned long offs); +void (*write_count)(void __iomem *base,unsigned long offs, +unsigned long value); +}; +struct sh_cmt_channel {struct sh_cmt_device *cmt;unsigned int index;
@@ -58,49 +104,16 @@ struct sh_cmt_channel {struct sh_cmt_device {struct platform_device *pdev; +const struct sh_cmt_info *info; +void __iomem *mapbase_ch;void __iomem *mapbase;struct clk *clk;struct sh_cmt_channel *channels;unsigned int num_channels; - -unsigned long width;/* 16 or 32 bit version of hardware block */ -unsigned long overflow_bit; -unsigned long clear_bits; - -/* callbacks for CMSTR and CMCSR access */ -unsigned long (*read_control)(void __iomem *base,unsigned long offs); -void (*write_control)(void __iomem *base,unsigned long offs, -unsigned long value); - -/* callbacks for CMCNT and CMCOR access */ -unsigned long (*read_count)(void __iomem *base,unsigned long offs); -void (*write_count)(void __iomem *base,unsigned long offs, -unsigned long value); }; -/* Examples of supported CMT timer register layouts and I/O access widths: -* -* "16-bit counter and 16-bit control" as found on sh7263: -* CMSTR 0xfffec000 16-bit -* CMCSR 0xfffec002 16-bit -* CMCNT 0xfffec004 16-bit -* CMCOR 0xfffec006 16-bit -* -* "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740: -* CMSTR 0xffca0000 16-bit -* CMCSR 0xffca0060 16-bit -* CMCNT 0xffca0064 32-bit -* CMCOR 0xffca0068 32-bit -* -* "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: -* CMSTR 0xffca0500 32-bit -* CMCSR 0xffca0510 32-bit -* CMCNT 0xffca0514 32-bit -* CMCOR 0xffca0518 32-bit -*/ -static unsigned long sh_cmt_read16 (void __iomem *base,unsigned long offs) {return ioread16 (base + (offs <<1 ));
@@ -123,47 +136,100 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,iowrite32 (value, base + (offs <<2 )); } +static const struct sh_cmt_info sh_cmt_info[] = { + [SH_CMT_16BIT ] = { + .model =SH_CMT_16BIT , + .width =16 , + .overflow_bit =0x80 , + .clear_bits = ~0x80 , + .read_control = sh_cmt_read16, + .write_control = sh_cmt_write16, + .read_count = sh_cmt_read16, + .write_count = sh_cmt_write16, + }, + [SH_CMT_32BIT ] = { + .model =SH_CMT_32BIT , + .width =32 , + .overflow_bit =0x8000 , + .clear_bits = ~0xc000 , + .read_control = sh_cmt_read16, + .write_control = sh_cmt_write16, + .read_count = sh_cmt_read32, + .write_count = sh_cmt_write32, + }, + [SH_CMT_32BIT_FAST ] = { + .model =SH_CMT_32BIT_FAST , + .width =32 , + .overflow_bit =0x8000 , + .clear_bits = ~0xc000 , + .read_control = sh_cmt_read16, + .write_control = sh_cmt_write16, + .read_count = sh_cmt_read32, + .write_count = sh_cmt_write32, + }, + [SH_CMT_48BIT ] = { + .model =SH_CMT_48BIT , + .width =32 , + .overflow_bit =0x8000 , + .clear_bits = ~0xc000 , + .read_control = sh_cmt_read32, + .write_control = sh_cmt_write32, + .read_count = sh_cmt_read32, + .write_count = sh_cmt_write32, + }, + [SH_CMT_48BIT_GEN2 ] = { + .model =SH_CMT_48BIT_GEN2 , + .width =32 , + .overflow_bit =0x8000 , + .clear_bits = ~0xc000 , + .read_control = sh_cmt_read32, + .write_control = sh_cmt_write32, + .read_count = sh_cmt_read32, + .write_count = sh_cmt_write32, + }, +}; +#define CMCSR 0/* channel register */ #define CMCNT 1/* channel register */ #define CMCOR 2/* channel register */ static inline unsigned long sh_cmt_read_cmstr (struct sh_cmt_channel *ch) { -return ch->cmt->read_control (ch->cmt->mapbase,0 ); +return ch->cmt->info->read_control (ch->cmt->mapbase,0 ); }static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) { -return ch->cmt->read_control (ch->base,CMCSR ); +return ch->cmt->info->read_control (ch->base,CMCSR ); }static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) { -return ch->cmt->read_count (ch->base,CMCNT ); +return ch->cmt->info->read_count (ch->base,CMCNT ); }static inline void sh_cmt_write_cmstr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_control (ch->cmt->mapbase,0 , value); + ch->cmt->info->write_control (ch->cmt->mapbase,0 , value); }static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_control (ch->base,CMCSR , value); + ch->cmt->info->write_control (ch->base,CMCSR , value); }static inline void sh_cmt_write_cmcnt (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->base,CMCNT , value); + ch->cmt->info->write_count (ch->base,CMCNT , value); }static inline void sh_cmt_write_cmcor (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->write_count (ch->base,CMCOR , value); + ch->cmt->info->write_count (ch->base,CMCOR , value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
@@ -172,7 +238,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,unsigned long v1, v2, v3;int o1, o2; - o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->overflow_bit; + o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->info->overflow_bit;/* Make sure the timer value is stable. Stolen from acpi_pm.c */ do {
@@ -180,7 +246,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, v1 =sh_cmt_read_cmcnt (ch); v2 =sh_cmt_read_cmcnt (ch); v3 =sh_cmt_read_cmcnt (ch); - o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->overflow_bit; + o1 =sh_cmt_read_cmcsr (ch) & ch->cmt->info->overflow_bit; }while (unlikely ((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
@@ -227,7 +293,7 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)sh_cmt_start_stop_ch (ch,0 );/* configure channel, periodic mode and maximum timeout */ -if (ch->cmt->width ==16 ) { +if (ch->cmt->info->width ==16 ) { *rate =clk_get_rate (ch->cmt->clk) /512 ;sh_cmt_write_cmcsr (ch,0x43 ); }else {
@@ -405,7 +471,8 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)struct sh_cmt_channel *ch = dev_id;/* clear flags */ -sh_cmt_write_cmcsr (ch,sh_cmt_read_cmcsr (ch) & ch->cmt->clear_bits); +sh_cmt_write_cmcsr (ch,sh_cmt_read_cmcsr (ch) & + ch->cmt->info->clear_bits);/* update clock source counter to begin with if enabled * the wrap flag should be cleared by the timer specific
@@ -719,10 +786,10 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,return irq; } -if (cmt->width == (sizeof (ch->max_match_value) *8 )) +if (cmt->info->width == (sizeof (ch->max_match_value) *8 )) ch->max_match_value = ~0 ;else - ch->max_match_value = (1 << cmt->width) -1 ; + ch->max_match_value = (1 << cmt->info->width) -1 ; ch->match_value = ch->max_match_value;raw_spin_lock_init (&ch->lock);
@@ -800,28 +867,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)if (ret <0 ) goto err3; -if (res2 && (resource_size (res2) ==4 )) { -/* assume both CMSTR and CMCSR to be 32-bit */ - cmt->read_control = sh_cmt_read32; - cmt->write_control = sh_cmt_write32; - }else { - cmt->read_control = sh_cmt_read16; - cmt->write_control = sh_cmt_write16; - } - -if (resource_size (res) ==6 ) { - cmt->width =16 ; - cmt->read_count = sh_cmt_read16; - cmt->write_count = sh_cmt_write16; - cmt->overflow_bit =0x80 ; - cmt->clear_bits = ~0x80 ; - }else { - cmt->width =32 ; - cmt->read_count = sh_cmt_read32; - cmt->write_count = sh_cmt_write32; - cmt->overflow_bit =0x8000 ; - cmt->clear_bits = ~0xc000 ; - } +/* identify the model based on the resources */ +if (resource_size (res) ==6 ) + cmt->info = &sh_cmt_info[SH_CMT_16BIT ]; +else if (res2 && (resource_size (res2) ==4 )) + cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2 ]; +else + cmt->info = &sh_cmt_info[SH_CMT_32BIT ]; cmt->channels =kzalloc (sizeof (*cmt->channels),GFP_KERNEL );if (cmt->channels ==NULL ) {
Signature · 1 line
1.7.9.5
PATCH 12/71 clocksource: sh_cmt: Replace hardcoded register values with macros
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Define symbolic macros for all used registers bits.
--- drivers/clocksource/sh_cmt.c | 56 +++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 12 deletions(-)
drivers/clocksource/sh_cmt.c +44 -12
@@ -114,6 +114,34 @@ struct sh_cmt_device {unsigned int num_channels; }; +#define SH_CMT16_CMCSR_CMF (1 << 7) +#define SH_CMT16_CMCSR_CMIE (1 << 6) +#define SH_CMT16_CMCSR_CKS8 (0 << 0) +#define SH_CMT16_CMCSR_CKS32 (1 << 0) +#define SH_CMT16_CMCSR_CKS128 (2 << 0) +#define SH_CMT16_CMCSR_CKS512 (3 << 0) +#define SH_CMT16_CMCSR_CKS_MASK (3 << 0) + +#define SH_CMT32_CMCSR_CMF (1 << 15) +#define SH_CMT32_CMCSR_OVF (1 << 14) +#define SH_CMT32_CMCSR_WRFLG (1 << 13) +#define SH_CMT32_CMCSR_STTF (1 << 12) +#define SH_CMT32_CMCSR_STPF (1 << 11) +#define SH_CMT32_CMCSR_SSIE (1 << 10) +#define SH_CMT32_CMCSR_CMS (1 << 9) +#define SH_CMT32_CMCSR_CMM (1 << 8) +#define SH_CMT32_CMCSR_CMTOUT_IE (1 << 7) +#define SH_CMT32_CMCSR_CMR_NONE (0 << 4) +#define SH_CMT32_CMCSR_CMR_DMA (1 << 4) +#define SH_CMT32_CMCSR_CMR_IRQ (2 << 4) +#define SH_CMT32_CMCSR_CMR_MASK (3 << 4) +#define SH_CMT32_CMCSR_DBGIVD (1 << 3) +#define SH_CMT32_CMCSR_CKS_RCLK8 (4 << 0) +#define SH_CMT32_CMCSR_CKS_RCLK32 (5 << 0) +#define SH_CMT32_CMCSR_CKS_RCLK128 (6 << 0) +#define SH_CMT32_CMCSR_CKS_RCLK1 (7 << 0) +#define SH_CMT32_CMCSR_CKS_MASK (7 << 0) +static unsigned long sh_cmt_read16 (void __iomem *base,unsigned long offs) {return ioread16 (base + (offs <<1 ));
@@ -140,8 +168,8 @@ static const struct sh_cmt_info sh_cmt_info[] = { [SH_CMT_16BIT] = { .model = SH_CMT_16BIT, .width = 16, - .overflow_bit = 0x80, - .clear_bits = ~0x80, + .overflow_bit = SH_CMT16_CMCSR_CMF, + .clear_bits = ~SH_CMT16_CMCSR_CMF, .read_control = sh_cmt_read16, .write_control = sh_cmt_write16, .read_count = sh_cmt_read16,
@@ -150,8 +178,8 @@ static const struct sh_cmt_info sh_cmt_info[] = { [SH_CMT_32BIT] = { .model = SH_CMT_32BIT, .width = 32, - .overflow_bit = 0x8000, - .clear_bits = ~0xc000, + .overflow_bit = SH_CMT32_CMCSR_CMF, + .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF), .read_control = sh_cmt_read16, .write_control = sh_cmt_write16, .read_count = sh_cmt_read32,
@@ -160,8 +188,8 @@ static const struct sh_cmt_info sh_cmt_info[] = { [SH_CMT_32BIT_FAST] = { .model = SH_CMT_32BIT_FAST, .width = 32, - .overflow_bit = 0x8000, - .clear_bits = ~0xc000, + .overflow_bit = SH_CMT32_CMCSR_CMF, + .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF), .read_control = sh_cmt_read16, .write_control = sh_cmt_write16, .read_count = sh_cmt_read32,
@@ -170,8 +198,8 @@ static const struct sh_cmt_info sh_cmt_info[] = { [SH_CMT_48BIT] = { .model = SH_CMT_48BIT, .width = 32, - .overflow_bit = 0x8000, - .clear_bits = ~0xc000, + .overflow_bit = SH_CMT32_CMCSR_CMF, + .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF), .read_control = sh_cmt_read32, .write_control = sh_cmt_write32, .read_count = sh_cmt_read32,
@@ -180,8 +208,8 @@ static const struct sh_cmt_info sh_cmt_info[] = { [SH_CMT_48BIT_GEN2] = { .model = SH_CMT_48BIT_GEN2, .width = 32, - .overflow_bit = 0x8000, - .clear_bits = ~0xc000, + .overflow_bit = SH_CMT32_CMCSR_CMF, + .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF), .read_control = sh_cmt_read32, .write_control = sh_cmt_write32, .read_count = sh_cmt_read32,
@@ -295,10 +323,14 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)/* configure channel, periodic mode and maximum timeout */ if (ch->cmt->info->width ==16 ) { *rate =clk_get_rate (ch->cmt->clk) /512 ; -sh_cmt_write_cmcsr (ch,0x43 ); +sh_cmt_write_cmcsr (ch,SH_CMT16_CMCSR_CMIE | +SH_CMT16_CMCSR_CKS512 ); }else { *rate =clk_get_rate (ch->cmt->clk) /8 ; -sh_cmt_write_cmcsr (ch,0x01a4 ); +sh_cmt_write_cmcsr (ch,SH_CMT32_CMCSR_CMM | +SH_CMT32_CMCSR_CMTOUT_IE | +SH_CMT32_CMCSR_CMR_IRQ | +SH_CMT32_CMCSR_CKS_RCLK8 ); }sh_cmt_write_cmcor (ch,0xffffffff );
Signature · 1 line
1.7.9.5
PATCH 13/71 clocksource: sh_cmt: Set cpumask to cpu_possible_mask
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The CMT is a global timer not restricted to a single CPU. It has a lower rating than the TMU or ARM architected timer, but is still useful on systems where the other timers are stopped during CPU sleep.
When multiple timers are available the timers core selects which timer to use based on timer ratings.
On SMP systems where timer broadcasting is required, one dummy timer is instantiated per CPU with a rating of 100. On those systems the CMT timer has a rating of 80, which makes the dummy timer selected by default on all CPUs. The CMT is then available, and will be used as a broadcast timer.
On UP systems no dummy timer is instantiated. The CMT timer has a rating of 125 on those systems and is used directly as a clock event device for CPU0 without broadcasting.
The CMT rating shouldn't depend on whether we boot a UP or SMP system. We can't raise the CMT rating to 125 on SMP systems. This would select CMT as the clock event device for CPU0 as its rating is higher than the dummy timer rating, and would leave the system without a broadcast timer. We could instead lower the rating to 80 on all systems, but that wouldn't reflect reality as ratings between 1 and 99 are documented as "unfit for real use".
We should raise the rating above 99 and still have the CMT selected as a broadcast timer. This can be done by changing the cpumask from cpumask_of(0) to cpu_possible_mask. In that case the timer selection logic will prefer the previously probed and already selected dummy timer for all CPUs based on the fact that already selected per-cpu timers are preferred over new global timers, regardless of their respective ratings. This also better reflects reality, as the CMT is not tied to the boot CPU.
Ideally the timer selection logic should realize that the CMT needs to be used as a broadcast timer on SMP systems as no other broadcast timer is available, regardless of the cpumask and rating.
--- drivers/clocksource/sh_cmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/sh_cmt.c +1 -1
@@ -776,7 +776,7 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->features |=CLOCK_EVT_FEAT_ONESHOT ; ced->rating = rating; - ced->cpumask =cpumask_of (0 ); + ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_cmt_clock_event_next; ced->set_mode = sh_cmt_clock_event_mode; ced->suspend = sh_cmt_clock_event_suspend;
Signature · 1 line
1.7.9.5
PATCH 14/71 clocksource: sh_cmt: Hardcode CMT clock event rating to 125
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
All boards use or should use a clock event rating of 125 for the CMT, hardcode it in the driver.
--- drivers/clocksource/sh_cmt.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/clocksource/sh_cmt.c +6 -7
@@ -768,14 +768,14 @@ static void sh_cmt_clock_event_resume(struct clock_event_device *ced) }static void sh_cmt_register_clockevent (struct sh_cmt_channel *ch, -const char *name,unsigned long rating) +const char *name) {struct clock_event_device *ced = &ch->ced; ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->features |=CLOCK_EVT_FEAT_ONESHOT ; - ced->rating = rating; + ced->rating =125 ; ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_cmt_clock_event_next; ced->set_mode = sh_cmt_clock_event_mode;
@@ -788,11 +788,10 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, }static int sh_cmt_register (struct sh_cmt_channel *ch,const char *name, -unsigned long clockevent_rating, -unsigned long clocksource_rating) +bool clockevent,unsigned long clocksource_rating) { -if (clockevent_rating) -sh_cmt_register_clockevent (ch, name, clockevent_rating); +if (clockevent) +sh_cmt_register_clockevent (ch, name);if (clocksource_rating)sh_cmt_register_clocksource (ch, name, clocksource_rating);
@@ -827,7 +826,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,raw_spin_lock_init (&ch->lock); ret =sh_cmt_register (ch,dev_name (&cmt->pdev->dev), - cfg->clockevent_rating, + cfg->clockevent_rating !=0 , cfg->clocksource_rating);if (ret) { dev_err(&cmt->pdev->dev, "ch%u: registration failed\n",
Signature · 1 line
1.7.9.5
PATCH 15/71 clocksource: sh_cmt: Hardcode CMT clock source rating to 125
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
All boards use or should use a clock source rating of 125 for the CMT, hardcode it in the driver.
--- drivers/clocksource/sh_cmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/clocksource/sh_cmt.c +6 -6
@@ -656,12 +656,12 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs) }static int sh_cmt_register_clocksource (struct sh_cmt_channel *ch, -const char *name,unsigned long rating) +const char *name) {struct clocksource *cs = &ch->cs; cs->name = name; - cs->rating = rating; + cs->rating =125 ; cs->read = sh_cmt_clocksource_read; cs->enable = sh_cmt_clocksource_enable; cs->disable = sh_cmt_clocksource_disable;
@@ -788,13 +788,13 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, }static int sh_cmt_register (struct sh_cmt_channel *ch,const char *name, -bool clockevent,unsigned long clocksource_rating) +bool clockevent,bool clocksource) {if (clockevent)sh_cmt_register_clockevent (ch, name); -if (clocksource_rating) -sh_cmt_register_clocksource (ch, name, clocksource_rating); +if (clocksource) +sh_cmt_register_clocksource (ch, name);return 0 ; }
@@ -827,7 +827,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, ret =sh_cmt_register (ch,dev_name (&cmt->pdev->dev), cfg->clockevent_rating !=0 , - cfg->clocksource_rating); + cfg->clocksource_rating !=0 );if (ret) {dev_err (&cmt->pdev->dev,"ch%u: registration failed\n" , ch->index);
Signature · 1 line
1.7.9.5
PATCH 16/71 clocksource: sh_cmt: Add support for multiple channels per device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
CMT hardware devices can support multiple channels, with global registers and per-channel registers. The sh_cmt driver currently models the hardware with one Linux device per channel. This model makes it difficult to handle global registers in a clean way.
Add support for a new model that uses one Linux device per timer with multiple channels per device. This requires changes to platform data, add new channel configuration fields.
Support for the legacy model is kept and will be removed after all platforms switch to the new model.
--- drivers/clocksource/sh_cmt.c | 304 ++++++++++++++++++++++++++++++++---------- include/linux/sh_timer.h | 1 + 2 files changed, 237 insertions(+), 68 deletions(-)
drivers/clocksource/sh_cmt.c +236 -68
@@ -53,7 +53,16 @@ struct sh_cmt_device;* channel registers block. All other versions have a shared start/stop register * located in the global space. * -* Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit +* Channels are indexed from 0 to N-1 in the documentation. The channel index +* infers the start/stop bit position in the control register and the channel +* registers block address. Some CMT instances have a subset of channels +* available, in which case the index in the documentation doesn't match the +* "real" index as implemented in hardware. This is for instance the case with +* CMT0 on r8a7740, which is a 32-bit variant with a single channel numbered 0 +* in the documentation but using start/stop bit 5 and having its registers +* block at 0x60. +* +* Similarly CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable. */
@@ -85,10 +94,14 @@ struct sh_cmt_info {struct sh_cmt_channel {struct sh_cmt_device *cmt; -unsigned int index; -void __iomem *base; +unsigned int index;/* Index in the documentation */ +unsigned int hwidx;/* Real hardware index */ + +void __iomem *iostart; +void __iomem *ioctrl; +unsigned int timer_bit;unsigned long flags;unsigned long match_value;unsigned long next_match_value;
@@ -105,6 +118,7 @@ struct sh_cmt_device {struct platform_device *pdev;const struct sh_cmt_info *info; +bool legacy;void __iomem *mapbase_ch;void __iomem *mapbase;
@@ -112,6 +126,9 @@ struct sh_cmt_device {struct sh_cmt_channel *channels;unsigned int num_channels; + +bool has_clockevent; +bool has_clocksource; };#define SH_CMT16_CMCSR_CMF (1 << 7)
@@ -223,41 +240,47 @@ static const struct sh_cmt_info sh_cmt_info[] = {static inline unsigned long sh_cmt_read_cmstr (struct sh_cmt_channel *ch) { -return ch->cmt->info->read_control (ch->cmt->mapbase,0 ); +if (ch->iostart) +return ch->cmt->info->read_control (ch->iostart,0 ); +else +return ch->cmt->info->read_control (ch->cmt->mapbase,0 ); } -static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) +static inline void sh_cmt_write_cmstr (struct sh_cmt_channel *ch, +unsigned long value) { -return ch->cmt->info->read_control (ch->base,CMCSR ); +if (ch->iostart) + ch->cmt->info->write_control (ch->iostart,0 , value); +else + ch->cmt->info->write_control (ch->cmt->mapbase,0 , value); } -static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) +static inline unsigned long sh_cmt_read_cmcsr (struct sh_cmt_channel *ch) { -return ch->cmt->info->read_count (ch->base,CMCNT ); +return ch->cmt->info->read_control (ch->ioctrl,CMCSR ); } -static inline void sh_cmt_write_cmstr (struct sh_cmt_channel *ch, +static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->info->write_control (ch->cmt->mapbase,0 , value); + ch->cmt->info->write_control (ch->ioctrl,CMCSR , value); } -static inline void sh_cmt_write_cmcsr (struct sh_cmt_channel *ch, -unsigned long value) +static inline unsigned long sh_cmt_read_cmcnt (struct sh_cmt_channel *ch) { - ch->cmt->info->write_control (ch->base,CMCSR , value); +return ch->cmt->info->read_count (ch->ioctrl,CMCNT ); }static inline void sh_cmt_write_cmcnt (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->info->write_count (ch->base,CMCNT , value); + ch->cmt->info->write_count (ch->ioctrl,CMCNT , value); }static inline void sh_cmt_write_cmcor (struct sh_cmt_channel *ch,unsigned long value) { - ch->cmt->info->write_count (ch->base,CMCOR , value); + ch->cmt->info->write_count (ch->ioctrl,CMCOR , value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
@@ -286,7 +309,6 @@ static DEFINE_RAW_SPINLOCK(sh_cmt_lock);static void sh_cmt_start_stop_ch (struct sh_cmt_channel *ch,int start) { -struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */
@@ -294,9 +316,9 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) value =sh_cmt_read_cmstr (ch);if (start) - value |=1 << cfg->timer_bit; + value |=1 << ch->timer_bit;else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << ch->timer_bit);sh_cmt_write_cmstr (ch, value);raw_spin_unlock_irqrestore (&sh_cmt_lock, flags);
@@ -790,27 +812,72 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,static int sh_cmt_register (struct sh_cmt_channel *ch,const char *name,bool clockevent,bool clocksource) { -if (clockevent) +if (clockevent) { + ch->cmt->has_clockevent = true;sh_cmt_register_clockevent (ch, name); + } -if (clocksource) +if (clocksource) { + ch->cmt->has_clocksource = true;sh_cmt_register_clocksource (ch, name); + }return 0 ; }static int sh_cmt_setup_channel (struct sh_cmt_channel *ch,unsigned int index, -struct sh_cmt_device *cmt) +unsigned int hwidx,bool clockevent, +bool clocksource,struct sh_cmt_device *cmt) { -struct sh_timer_config *cfg = cmt->pdev->dev.platform_data;int irq;int ret; +/* Skip unused channels. */ +if (!clockevent && !clocksource) +return 0 ; + ch->cmt = cmt; - ch->base = cmt->mapbase_ch; ch->index = index; + ch->hwidx = hwidx; + +/* +* Compute the address of the channel control register block. For the +* timers with a per-channel start/stop register, compute its address +* as well. +* +* For legacy configuration the address has been mapped explicitly. +*/ +if (cmt->legacy) { + ch->ioctrl = cmt->mapbase_ch; + }else { +switch (cmt->info->model) { +case SH_CMT_16BIT : + ch->ioctrl = cmt->mapbase +2 + ch->hwidx *6 ; +break ; +case SH_CMT_32BIT : +case SH_CMT_48BIT : + ch->ioctrl = cmt->mapbase +0x10 + ch->hwidx *0x10 ; +break ; +case SH_CMT_32BIT_FAST : +/* +* The 32-bit "fast" timer has a single channel at hwidx +* 5 but is located at offset 0x40 instead of 0x60 for +* some reason. +*/ + ch->ioctrl = cmt->mapbase +0x40 ; +break ; +case SH_CMT_48BIT_GEN2 : + ch->iostart = cmt->mapbase + ch->hwidx *0x100 ; + ch->ioctrl = ch->iostart +0x10 ; +break ; + } + } + +if (cmt->legacy) + irq =platform_get_irq (cmt->pdev,0 ); +else + irq =platform_get_irq (cmt->pdev, ch->index); - irq =platform_get_irq (cmt->pdev,0 );if (irq <0 ) {dev_err (&cmt->pdev->dev,"ch%u: failed to get irq\n" , ch->index);
@@ -825,9 +892,15 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, ch->match_value = ch->max_match_value;raw_spin_lock_init (&ch->lock); +if (cmt->legacy) { + ch->timer_bit = ch->hwidx; + }else { + ch->timer_bit = cmt->info->model ==SH_CMT_48BIT_GEN2 + ?0 : ch->hwidx; + } + ret =sh_cmt_register (ch,dev_name (&cmt->pdev->dev), - cfg->clockevent_rating !=0 , - cfg->clocksource_rating !=0 ); + clockevent, clocksource);if (ret) {dev_err (&cmt->pdev->dev,"ch%u: registration failed\n" , ch->index);
@@ -847,97 +920,180 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,return 0 ; } -static int sh_cmt_setup (struct sh_cmt_device *cmt,struct platform_device *pdev) +static int sh_cmt_map_memory (struct sh_cmt_device *cmt) { -struct sh_timer_config *cfg = pdev->dev.platform_data; -struct resource *res, *res2; -int ret; - ret = -ENXIO ; +struct resource *mem; - cmt->pdev = pdev; + mem =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,0 ); +if (!mem) { +dev_err (&cmt->pdev->dev,"failed to get I/O memory\n" ); +return -ENXIO ; + } -if (!cfg) { -dev_err (&cmt->pdev->dev,"missing platform data\n" ); - goto err0; + cmt->mapbase =ioremap_nocache (mem->start,resource_size (mem)); +if (cmt->mapbase ==NULL ) { +dev_err (&cmt->pdev->dev,"failed to remap I/O memory\n" ); +return -ENXIO ; } +return 0 ; +} + +static int sh_cmt_map_memory_legacy (struct sh_cmt_device *cmt) +{ +struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; +struct resource *res, *res2; + +/* map memory, let mapbase_ch point to our channel */ res =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,0 );if (!res) {dev_err (&cmt->pdev->dev,"failed to get I/O memory\n" ); - goto err0; +return -ENXIO ; } -/* optional resource for the shared timer start/stop register */ - res2 =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,1 ); - -/* map memory, let mapbase_ch point to our channel */ cmt->mapbase_ch =ioremap_nocache (res->start,resource_size (res));if (cmt->mapbase_ch ==NULL ) {dev_err (&cmt->pdev->dev,"failed to remap I/O memory\n" ); - goto err0; +return -ENXIO ; } +/* optional resource for the shared timer start/stop register */ + res2 =platform_get_resource (cmt->pdev,IORESOURCE_MEM ,1 ); +/* map second resource for CMSTR */ cmt->mapbase =ioremap_nocache (res2 ? res2->start : res->start - cfg->channel_offset, res2 ?resource_size (res2) :2 );if (cmt->mapbase ==NULL ) {dev_err (&cmt->pdev->dev,"failed to remap I/O second memory\n" ); - goto err1; +iounmap (cmt->mapbase_ch); +return -ENXIO ; } -/* get hold of clock */ +/* identify the model based on the resources */ +if (resource_size (res) ==6 ) + cmt->info = &sh_cmt_info[SH_CMT_16BIT ]; +else if (res2 && (resource_size (res2) ==4 )) + cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2 ]; +else + cmt->info = &sh_cmt_info[SH_CMT_32BIT ]; + +return 0 ; +} + +static void sh_cmt_unmap_memory (struct sh_cmt_device *cmt) +{ +iounmap (cmt->mapbase); +if (cmt->mapbase_ch) +iounmap (cmt->mapbase_ch); +} + +static int sh_cmt_setup (struct sh_cmt_device *cmt,struct platform_device *pdev) +{ +struct sh_timer_config *cfg = pdev->dev.platform_data; +const struct platform_device_id *id = pdev->id_entry; +unsigned int hw_channels; +int ret; + +memset (cmt,0 ,sizeof (*cmt)); + cmt->pdev = pdev; + +if (!cfg) { +dev_err (&cmt->pdev->dev,"missing platform data\n" ); +return -ENXIO ; + } + + cmt->info = (const struct sh_cmt_info *)id->driver_data; + cmt->legacy = cmt->info ? false : true; + +/* Get hold of clock. */ cmt->clk =clk_get (&cmt->pdev->dev,"cmt_fck" );if (IS_ERR (cmt->clk)) {dev_err (&cmt->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (cmt->clk); - goto err2; +return PTR_ERR (cmt->clk); } ret =clk_prepare (cmt->clk);if (ret <0 ) - goto err3; + goto err_clk_put; -/* identify the model based on the resources */ -if (resource_size (res) ==6 ) - cmt->info = &sh_cmt_info[SH_CMT_16BIT ]; -else if (res2 && (resource_size (res2) ==4 )) - cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2 ]; +/* +* Map the memory resource(s). We need to support both the legacy +* platform device configuration (with one device per channel) and the +* new version (with multiple channels per device). +*/ +if (cmt->legacy) + ret =sh_cmt_map_memory_legacy (cmt);else - cmt->info = &sh_cmt_info[SH_CMT_32BIT ]; + ret =sh_cmt_map_memory (cmt); - cmt->channels =kzalloc (sizeof (*cmt->channels),GFP_KERNEL ); +if (ret <0 ) + goto err_clk_unprepare; + +/* Allocate and setup the channels. */ +if (cmt->legacy) { + cmt->num_channels =1 ; + hw_channels =0 ; + }else { + cmt->num_channels =hweight8 (cfg->channels_mask); + hw_channels = cfg->channels_mask; + } + + cmt->channels =kzalloc (cmt->num_channels *sizeof (*cmt->channels), +GFP_KERNEL );if (cmt->channels ==NULL ) { ret = -ENOMEM ; - goto err4; + goto err_unmap; } - cmt->num_channels =1 ; +if (cmt->legacy) { + ret =sh_cmt_setup_channel (&cmt->channels[0 ], + cfg->timer_bit, cfg->timer_bit, + cfg->clockevent_rating !=0 , + cfg->clocksource_rating !=0 , cmt); +if (ret <0 ) + goto err_unmap; + }else { +unsigned int mask = hw_channels; +unsigned int i; - ret =sh_cmt_setup_channel (&cmt->channels[0 ], cfg->timer_bit, cmt); -if (ret <0 ) - goto err4; +/* +* Use the first channel as a clock event device and the second +* channel as a clock source. If only one channel is available +* use it for both. +*/ +for (i =0 ; i < cmt->num_channels; ++i) { +unsigned int hwidx =ffs (mask) -1 ; +bool clocksource = i ==1 || cmt->num_channels ==1 ; +bool clockevent = i ==0 ; + + ret =sh_cmt_setup_channel (&cmt->channels[i], i, hwidx, + clockevent, clocksource, + cmt); +if (ret <0 ) + goto err_unmap; + + mask &= ~(1 << hwidx); + } + }platform_set_drvdata (pdev, cmt);return 0 ; -err4: + +err_unmap:kfree (cmt->channels); +sh_cmt_unmap_memory (cmt); +err_clk_unprepare:clk_unprepare (cmt->clk); -err3: +err_clk_put:clk_put (cmt->clk); -err2: -iounmap (cmt->mapbase); -err1: -iounmap (cmt->mapbase_ch); -err0:return ret; }static int sh_cmt_probe (struct platform_device *pdev) {struct sh_cmt_device *cmt =platform_get_drvdata (pdev); -struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;if (!is_early_platform_device (pdev)) {
@@ -966,7 +1122,7 @@ static int sh_cmt_probe(struct platform_device *pdev)return 0 ; out: -if (cfg->clockevent_rating || cfg->clocksource_rating) +if (cmt->has_clockevent || cmt->has_clocksource)pm_runtime_irq_safe (&pdev->dev);else pm_runtime_idle (&pdev->dev);
@@ -979,12 +1135,24 @@ static int sh_cmt_remove(struct platform_device *pdev)return -EBUSY ;/* cannot unregister clockevent and clocksource */ } +static const struct platform_device_id sh_cmt_id_table[] = { + {"sh_cmt" ,0 }, + {"sh-cmt-16" , (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT ] }, + {"sh-cmt-32" , (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT ] }, + {"sh-cmt-32-fast" , (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST ] }, + {"sh-cmt-48" , (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT ] }, + {"sh-cmt-48-gen2" , (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2 ] }, + { } +}; +MODULE_DEVICE_TABLE (platform, sh_cmt_id_table); +static struct platform_driver sh_cmt_device_driver = { .probe = sh_cmt_probe, .remove = sh_cmt_remove, .driver = { .name ="sh_cmt" , - } + }, + .id_table = sh_cmt_id_table, };static int __init sh_cmt_init (void )
include/linux/sh_timer.h +1 -0
@@ -7,6 +7,7 @@ struct sh_timer_config {int timer_bit;unsigned long clockevent_rating;unsigned long clocksource_rating; + unsigned int channels_mask; };#endif /* __SH_TIMER_H__ */
Signature · 1 line
1.7.9.5
PATCH 17/71 clocksource: sh_cmt: Rename clock to "fck" in the non-legacy case
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The sh_cmt driver gets the CMT functional clock using a connection ID of "cmt_fck". While all SH SoCs create clock lookup entries with a NULL device ID and a "cmt_fck" connection ID, the ARM SoCs use the device ID only with a NULL connection ID. This works on legacy platforms but will break on ARM with DT boot.
Fix the situation by using a connection ID of "fck" in the non-legacy platform data case. Clock lookup entries will be renamed to use the device ID as well as the connection ID as platforms get moved to new platform data. The legacy code will eventually be dropped, leaving us with device ID based clock lookup, compatible with DT boot.
--- drivers/clocksource/sh_cmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/sh_cmt.c +1 -1
@@ -1007,7 +1007,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) cmt->legacy = cmt->info ? false : true;/* Get hold of clock. */ - cmt->clk =clk_get (&cmt->pdev->dev,"cmt_fck" ); + cmt->clk =clk_get (&cmt->pdev->dev, cmt->legacy ?"cmt_fck" :"fck" );if (IS_ERR (cmt->clk)) {dev_err (&cmt->pdev->dev,"cannot get clock\n" );return PTR_ERR (cmt->clk);
Signature · 1 line
1.7.9.5
PATCH 18/71 clocksource: sh_cmt: Remove FSF mail address from GPL notice
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
--- drivers/clocksource/sh_cmt.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/clocksource/sh_cmt.c +0 -4
@@ -11,10 +11,6 @@* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h>
Signature · 1 line
1.7.9.5
PATCH 19/71 clocksource: sh_cmt: Sort headers alphabetically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This helps locating duplicates and inserting new headers.
--- drivers/clocksource/sh_cmt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
drivers/clocksource/sh_cmt.c +10 -10
@@ -13,23 +13,23 @@* GNU General Public License for more details. */ +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/ioport.h> #include <linux/io.h> -#include <linux/clk.h> +#include <linux/ioport.h> #include <linux/irq.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/sh_timer.h> -#include <linux/slab.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/sh_timer.h> +#include <linux/slab.h> +#include <linux/spinlock.h> struct sh_cmt_device ;
Signature · 1 line
1.7.9.5
PATCH 20/71 clocksource: sh_cmt: Request IRQ for clock event device only
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Clock sources don't need an IRQ, request the IRQ only for channels used as clock event devices.
--- drivers/clocksource/sh_cmt.c | 51 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 24 deletions(-)
drivers/clocksource/sh_cmt.c +27 -24
@@ -785,10 +785,28 @@ static void sh_cmt_clock_event_resume(struct clock_event_device *ced)pm_genpd_syscore_poweron (&ch->cmt->pdev->dev); } -static void sh_cmt_register_clockevent (struct sh_cmt_channel *ch, -const char *name) +static int sh_cmt_register_clockevent (struct sh_cmt_channel *ch, +const char *name) {struct clock_event_device *ced = &ch->ced; +int irq; +int ret; + + irq =platform_get_irq (ch->cmt->pdev, ch->cmt->legacy ?0 : ch->index); +if (irq <0 ) { +dev_err (&ch->cmt->pdev->dev,"ch%u: failed to get irq\n" , + ch->index); +return irq; + } + + ret =request_irq (irq, sh_cmt_interrupt, +IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , +dev_name (&ch->cmt->pdev->dev), ch); +if (ret) { +dev_err (&ch->cmt->pdev->dev,"ch%u: failed to request irq %d\n" , + ch->index, irq); +return ret; + } ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ;
@@ -803,14 +821,20 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,dev_info (&ch->cmt->pdev->dev,"ch%u: used for clock events\n" , ch->index);clockevents_register_device (ced); + +return 0 ; }static int sh_cmt_register (struct sh_cmt_channel *ch,const char *name,bool clockevent,bool clocksource) { +int ret; +if (clockevent) { ch->cmt->has_clockevent = true; -sh_cmt_register_clockevent (ch, name); + ret =sh_cmt_register_clockevent (ch, name); +if (ret <0 ) +return ret; }if (clocksource) {
@@ -825,7 +849,6 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, unsigned int hwidx, bool clockevent, bool clocksource, struct sh_cmt_device *cmt) { - int irq; int ret;/* Skip unused channels. */
@@ -869,17 +892,6 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, } } -if (cmt->legacy) - irq =platform_get_irq (cmt->pdev,0 ); -else - irq =platform_get_irq (cmt->pdev, ch->index); - -if (irq <0 ) { -dev_err (&cmt->pdev->dev,"ch%u: failed to get irq\n" , - ch->index); -return irq; - } -if (cmt->info->width == (sizeof (ch->max_match_value) *8 )) ch->max_match_value = ~0 ;else
@@ -904,15 +916,6 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, } ch->cs_enabled = false; - ret =request_irq (irq, sh_cmt_interrupt, -IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&cmt->pdev->dev), ch); -if (ret) { -dev_err (&cmt->pdev->dev,"ch%u: failed to request irq %d\n" , - ch->index, irq); -return ret; - } -return 0 ; }
Signature · 1 line
1.7.9.5
PATCH 21/71 clocksource: sh_tmu: Use request_irq() instead of setup_irq()
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The driver claims it needs to register an interrupt handler too early for request_irq(). This might have been true in the past, but the only meaningful difference between request_irq() and setup_irq() today is an additional kzalloc() call in request_irq(). As the driver calls kmalloc() itself we know that the slab allocator is available, we can thus switch to request_irq().
--- drivers/clocksource/sh_tmu.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-)
drivers/clocksource/sh_tmu.c +8 -14
@@ -38,7 +38,7 @@struct sh_tmu_priv {void __iomem *mapbase;struct clk *clk; -struct irqaction irqaction; +int irq;struct platform_device *pdev;unsigned long rate;unsigned long periodic;
@@ -401,10 +401,11 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,clockevents_config_and_register (ced,1 ,0x300 ,0xffffffff ); - ret =setup_irq (p->irqaction.irq, &p->irqaction); + ret =request_irq (p->irq, sh_tmu_interrupt, +IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , +dev_name (&p->pdev->dev), p);if (ret) { -dev_err (&p->pdev->dev,"failed to request irq %d\n" , - p->irqaction.irq); +dev_err (&p->pdev->dev,"failed to request irq %d\n" , p->irq);return ; } }
@@ -425,7 +426,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; -int irq, ret; +int ret; ret = -ENXIO ;memset (p,0 ,sizeof (*p));
@@ -444,8 +445,8 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) goto err0; } - irq =platform_get_irq (p->pdev,0 ); -if (irq <0 ) { + p->irq =platform_get_irq (p->pdev,0 ); +if (p->irq <0 ) {dev_err (&p->pdev->dev,"failed to get irq\n" ); goto err0; }
@@ -457,13 +458,6 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) goto err0; } -/* setup data for setup_irq() (too early for request_irq()) */ - p->irqaction.name =dev_name (&p->pdev->dev); - p->irqaction.handler = sh_tmu_interrupt; - p->irqaction.dev_id = p; - p->irqaction.irq = irq; - p->irqaction.flags =IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING ; -/* get hold of clock */ p->clk =clk_get (&p->pdev->dev,"tmu_fck" );if (IS_ERR (p->clk)) {
Signature · 1 line
1.7.9.5
PATCH 22/71 clocksource: sh_tmu: Split channel fields from sh_tmu_priv
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Create a new sh_tmu_channel structure to hold the channel-specific field in preparation for multiple channels per device support.
--- drivers/clocksource/sh_tmu.c | 235 ++++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 110 deletions(-)
drivers/clocksource/sh_tmu.c +125 -110
@@ -35,11 +35,13 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> -struct sh_tmu_priv { -void __iomem *mapbase; -struct clk *clk; +struct sh_tmu_priv ; + +struct sh_tmu_channel { +struct sh_tmu_priv *tmu; +int irq; -struct platform_device *pdev; +unsigned long rate;unsigned long periodic;struct clock_event_device ced;
@@ -48,6 +50,15 @@ struct sh_tmu_priv {unsigned int enable_count; }; +struct sh_tmu_priv { +struct platform_device *pdev; + +void __iomem *mapbase; +struct clk *clk; + +struct sh_tmu_channel channel; +}; +static DEFINE_RAW_SPINLOCK (sh_tmu_lock);#define TSTR -1/* shared register */
@@ -55,10 +66,10 @@ static DEFINE_RAW_SPINLOCK(sh_tmu_lock);#define TCNT 1/* channel register */ #define TCR 2/* channel register */ -static inline unsigned long sh_tmu_read (struct sh_tmu_priv *p,int reg_nr) +static inline unsigned long sh_tmu_read (struct sh_tmu_channel *ch,int reg_nr) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; -void __iomem *base = p->mapbase; +struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data; +void __iomem *base = ch->tmu->mapbase;unsigned long offs;if (reg_nr ==TSTR )
@@ -72,11 +83,11 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr)return ioread32 (base + offs); } -static inline void sh_tmu_write (struct sh_tmu_priv *p,int reg_nr, +static inline void sh_tmu_write (struct sh_tmu_channel *ch,int reg_nr,unsigned long value) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; -void __iomem *base = p->mapbase; +struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data; +void __iomem *base = ch->tmu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) {
@@ -92,152 +103,152 @@ static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr,iowrite32 (value, base + offs); } -static void sh_tmu_start_stop_ch (struct sh_tmu_priv *p,int start) +static void sh_tmu_start_stop_ch (struct sh_tmu_channel *ch,int start) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; +struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */ raw_spin_lock_irqsave (&sh_tmu_lock, flags); - value =sh_tmu_read (p,TSTR ); + value =sh_tmu_read (ch,TSTR );if (start) value |=1 << cfg->timer_bit;else value &= ~(1 << cfg->timer_bit); -sh_tmu_write (p,TSTR , value); +sh_tmu_write (ch,TSTR , value);raw_spin_unlock_irqrestore (&sh_tmu_lock, flags); } -static int __sh_tmu_enable (struct sh_tmu_priv *p) +static int __sh_tmu_enable (struct sh_tmu_channel *ch) {int ret;/* enable clock */ - ret =clk_enable (p->clk); + ret =clk_enable (ch->tmu->clk);if (ret) { -dev_err (&p->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->tmu->pdev->dev,"cannot enable clock\n" );return ret; }/* make sure channel is disabled */ -sh_tmu_start_stop_ch (p,0 ); +sh_tmu_start_stop_ch (ch,0 );/* maximum timeout */ -sh_tmu_write (p,TCOR ,0xffffffff ); -sh_tmu_write (p,TCNT ,0xffffffff ); +sh_tmu_write (ch,TCOR ,0xffffffff ); +sh_tmu_write (ch,TCNT ,0xffffffff );/* configure channel to parent clock / 4, irq off */ - p->rate =clk_get_rate (p->clk) /4 ; -sh_tmu_write (p,TCR ,0x0000 ); + ch->rate =clk_get_rate (ch->tmu->clk) /4 ; +sh_tmu_write (ch,TCR ,0x0000 );/* enable channel */ -sh_tmu_start_stop_ch (p,1 ); +sh_tmu_start_stop_ch (ch,1 );return 0 ; } -static int sh_tmu_enable (struct sh_tmu_priv *p) +static int sh_tmu_enable (struct sh_tmu_channel *ch) { -if (p->enable_count++ >0 ) +if (ch->enable_count++ >0 )return 0 ; -pm_runtime_get_sync (&p->pdev->dev); -dev_pm_syscore_device (&p->pdev->dev, true); +pm_runtime_get_sync (&ch->tmu->pdev->dev); +dev_pm_syscore_device (&ch->tmu->pdev->dev, true); -return __sh_tmu_enable (p); +return __sh_tmu_enable (ch); } -static void __sh_tmu_disable (struct sh_tmu_priv *p) +static void __sh_tmu_disable (struct sh_tmu_channel *ch) {/* disable channel */ -sh_tmu_start_stop_ch (p,0 ); +sh_tmu_start_stop_ch (ch,0 );/* disable interrupts in TMU block */ -sh_tmu_write (p,TCR ,0x0000 ); +sh_tmu_write (ch,TCR ,0x0000 );/* stop clock */ -clk_disable (p->clk); +clk_disable (ch->tmu->clk); } -static void sh_tmu_disable (struct sh_tmu_priv *p) +static void sh_tmu_disable (struct sh_tmu_channel *ch) { -if (WARN_ON (p->enable_count ==0 )) +if (WARN_ON (ch->enable_count ==0 ))return ; -if (--p->enable_count >0 ) +if (--ch->enable_count >0 )return ; -__sh_tmu_disable (p); +__sh_tmu_disable (ch); -dev_pm_syscore_device (&p->pdev->dev, false); -pm_runtime_put (&p->pdev->dev); +dev_pm_syscore_device (&ch->tmu->pdev->dev, false); +pm_runtime_put (&ch->tmu->pdev->dev); } -static void sh_tmu_set_next (struct sh_tmu_priv *p,unsigned long delta, +static void sh_tmu_set_next (struct sh_tmu_channel *ch,unsigned long delta,int periodic) {/* stop timer */ -sh_tmu_start_stop_ch (p,0 ); +sh_tmu_start_stop_ch (ch,0 );/* acknowledge interrupt */ -sh_tmu_read (p,TCR ); +sh_tmu_read (ch,TCR );/* enable interrupt */ -sh_tmu_write (p,TCR ,0x0020 ); +sh_tmu_write (ch,TCR ,0x0020 );/* reload delta value in case of periodic timer */ if (periodic) -sh_tmu_write (p,TCOR , delta); +sh_tmu_write (ch,TCOR , delta);else -sh_tmu_write (p,TCOR ,0xffffffff ); +sh_tmu_write (ch,TCOR ,0xffffffff ); -sh_tmu_write (p,TCNT , delta); +sh_tmu_write (ch,TCNT , delta);/* start timer */ -sh_tmu_start_stop_ch (p,1 ); +sh_tmu_start_stop_ch (ch,1 ); }static irqreturn_t sh_tmu_interrupt (int irq,void *dev_id) { -struct sh_tmu_priv *p = dev_id; +struct sh_tmu_channel *ch = dev_id;/* disable or acknowledge interrupt */ -if (p->ced.mode ==CLOCK_EVT_MODE_ONESHOT ) -sh_tmu_write (p,TCR ,0x0000 ); +if (ch->ced.mode ==CLOCK_EVT_MODE_ONESHOT ) +sh_tmu_write (ch,TCR ,0x0000 );else -sh_tmu_write (p,TCR ,0x0020 ); +sh_tmu_write (ch,TCR ,0x0020 );/* notify clockevent layer */ - p->ced.event_handler (&p->ced); + ch->ced.event_handler (&ch->ced);return IRQ_HANDLED ; } -static struct sh_tmu_priv *cs_to_sh_tmu (struct clocksource *cs) +static struct sh_tmu_channel *cs_to_sh_tmu (struct clocksource *cs) { - return container_of(cs, struct sh_tmu_priv, cs); + return container_of(cs, struct sh_tmu_channel, cs); }static cycle_t sh_tmu_clocksource_read (struct clocksource *cs) { -struct sh_tmu_priv *p =cs_to_sh_tmu (cs); +struct sh_tmu_channel *ch =cs_to_sh_tmu (cs); -return sh_tmu_read (p,TCNT ) ^0xffffffff ; +return sh_tmu_read (ch,TCNT ) ^0xffffffff ; }static int sh_tmu_clocksource_enable (struct clocksource *cs) { -struct sh_tmu_priv *p =cs_to_sh_tmu (cs); +struct sh_tmu_channel *ch =cs_to_sh_tmu (cs);int ret; -if (WARN_ON (p->cs_enabled)) +if (WARN_ON (ch->cs_enabled))return 0 ; - ret =sh_tmu_enable (p); + ret =sh_tmu_enable (ch);if (!ret) { -__clocksource_updatefreq_hz (cs, p->rate); - p->cs_enabled = true; +__clocksource_updatefreq_hz (cs, ch->rate); + ch->cs_enabled = true; }return ret;
@@ -245,45 +256,45 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)static void sh_tmu_clocksource_disable (struct clocksource *cs) { -struct sh_tmu_priv *p =cs_to_sh_tmu (cs); +struct sh_tmu_channel *ch =cs_to_sh_tmu (cs); -if (WARN_ON (!p->cs_enabled)) +if (WARN_ON (!ch->cs_enabled))return ; -sh_tmu_disable (p); - p->cs_enabled = false; +sh_tmu_disable (ch); + ch->cs_enabled = false; }static void sh_tmu_clocksource_suspend (struct clocksource *cs) { -struct sh_tmu_priv *p =cs_to_sh_tmu (cs); +struct sh_tmu_channel *ch =cs_to_sh_tmu (cs); -if (!p->cs_enabled) +if (!ch->cs_enabled)return ; -if (--p->enable_count ==0 ) { -__sh_tmu_disable (p); -pm_genpd_syscore_poweroff (&p->pdev->dev); +if (--ch->enable_count ==0 ) { +__sh_tmu_disable (ch); +pm_genpd_syscore_poweroff (&ch->tmu->pdev->dev); } }static void sh_tmu_clocksource_resume (struct clocksource *cs) { -struct sh_tmu_priv *p =cs_to_sh_tmu (cs); +struct sh_tmu_channel *ch =cs_to_sh_tmu (cs); -if (!p->cs_enabled) +if (!ch->cs_enabled)return ; -if (p->enable_count++ ==0 ) { -pm_genpd_syscore_poweron (&p->pdev->dev); -__sh_tmu_enable (p); +if (ch->enable_count++ ==0 ) { +pm_genpd_syscore_poweron (&ch->tmu->pdev->dev); +__sh_tmu_enable (ch); } } -static int sh_tmu_register_clocksource (struct sh_tmu_priv *p, +static int sh_tmu_register_clocksource (struct sh_tmu_channel *ch,char *name,unsigned long rating) { -struct clocksource *cs = &p->cs; +struct clocksource *cs = &ch->cs; cs->name = name; cs->rating = rating;
@@ -295,43 +306,43 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, cs->mask =CLOCKSOURCE_MASK (32 ); cs->flags =CLOCK_SOURCE_IS_CONTINUOUS ; -dev_info (&p->pdev->dev,"used as clock source\n" ); +dev_info (&ch->tmu->pdev->dev,"used as clock source\n" );/* Register with dummy 1 Hz value, gets updated in ->enable() */ clocksource_register_hz (cs,1 );return 0 ; } -static struct sh_tmu_priv *ced_to_sh_tmu (struct clock_event_device *ced) +static struct sh_tmu_channel *ced_to_sh_tmu (struct clock_event_device *ced) { - return container_of(ced, struct sh_tmu_priv, ced); + return container_of(ced, struct sh_tmu_channel, ced); } -static void sh_tmu_clock_event_start (struct sh_tmu_priv *p,int periodic) +static void sh_tmu_clock_event_start (struct sh_tmu_channel *ch,int periodic) { -struct clock_event_device *ced = &p->ced; +struct clock_event_device *ced = &ch->ced; -sh_tmu_enable (p); +sh_tmu_enable (ch); -clockevents_config (ced, p->rate); +clockevents_config (ced, ch->rate);if (periodic) { - p->periodic = (p->rate +HZ /2 ) /HZ ; -sh_tmu_set_next (p, p->periodic,1 ); + ch->periodic = (ch->rate +HZ /2 ) /HZ ; +sh_tmu_set_next (ch, ch->periodic,1 ); } }static void sh_tmu_clock_event_mode (enum clock_event_mode mode,struct clock_event_device *ced) { -struct sh_tmu_priv *p =ced_to_sh_tmu (ced); +struct sh_tmu_channel *ch =ced_to_sh_tmu (ced);int disabled =0 ;/* deal with old setting first */ switch (ced->mode) {case CLOCK_EVT_MODE_PERIODIC :case CLOCK_EVT_MODE_ONESHOT : -sh_tmu_disable (p); +sh_tmu_disable (ch); disabled =1 ;break ;default :
@@ -340,16 +351,18 @@ static void sh_tmu_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC : -dev_info (&p->pdev->dev,"used for periodic clock events\n" ); -sh_tmu_clock_event_start (p,1 ); +dev_info (&ch->tmu->pdev->dev, +"used for periodic clock events\n" ); +sh_tmu_clock_event_start (ch,1 );break ;case CLOCK_EVT_MODE_ONESHOT : -dev_info (&p->pdev->dev,"used for oneshot clock events\n" ); -sh_tmu_clock_event_start (p,0 ); +dev_info (&ch->tmu->pdev->dev, +"used for oneshot clock events\n" ); +sh_tmu_clock_event_start (ch,0 );break ;case CLOCK_EVT_MODE_UNUSED :if (!disabled) -sh_tmu_disable (p); +sh_tmu_disable (ch);break ;case CLOCK_EVT_MODE_SHUTDOWN :default :
@@ -360,29 +373,29 @@ static void sh_tmu_clock_event_mode(enum clock_event_mode mode,static int sh_tmu_clock_event_next (unsigned long delta,struct clock_event_device *ced) { -struct sh_tmu_priv *p =ced_to_sh_tmu (ced); +struct sh_tmu_channel *ch =ced_to_sh_tmu (ced);BUG_ON (ced->mode !=CLOCK_EVT_MODE_ONESHOT );/* program new delta value */ -sh_tmu_set_next (p, delta,0 ); +sh_tmu_set_next (ch, delta,0 );return 0 ; }static void sh_tmu_clock_event_suspend (struct clock_event_device *ced) { -pm_genpd_syscore_poweroff (&ced_to_sh_tmu (ced)->pdev->dev); +pm_genpd_syscore_poweroff (&ced_to_sh_tmu (ced)->tmu->pdev->dev); }static void sh_tmu_clock_event_resume (struct clock_event_device *ced) { -pm_genpd_syscore_poweron (&ced_to_sh_tmu (ced)->pdev->dev); +pm_genpd_syscore_poweron (&ced_to_sh_tmu (ced)->tmu->pdev->dev); } -static void sh_tmu_register_clockevent (struct sh_tmu_priv *p, +static void sh_tmu_register_clockevent (struct sh_tmu_channel *ch,char *name,unsigned long rating) { -struct clock_event_device *ced = &p->ced; +struct clock_event_device *ced = &ch->ced;int ret;memset (ced,0 ,sizeof (*ced));
@@ -397,27 +410,28 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, ced->suspend = sh_tmu_clock_event_suspend; ced->resume = sh_tmu_clock_event_resume; -dev_info (&p->pdev->dev,"used for clock events\n" ); +dev_info (&ch->tmu->pdev->dev,"used for clock events\n" );clockevents_config_and_register (ced,1 ,0x300 ,0xffffffff ); - ret =request_irq (p->irq, sh_tmu_interrupt, + ret =request_irq (ch->irq, sh_tmu_interrupt,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&p->pdev->dev), p); +dev_name (&ch->tmu->pdev->dev), ch);if (ret) { -dev_err (&p->pdev->dev,"failed to request irq %d\n" , p->irq); +dev_err (&ch->tmu->pdev->dev,"failed to request irq %d\n" , + ch->irq);return ; } } -static int sh_tmu_register (struct sh_tmu_priv *p,char *name, +static int sh_tmu_register (struct sh_tmu_channel *ch,char *name,unsigned long clockevent_rating,unsigned long clocksource_rating) {if (clockevent_rating) -sh_tmu_register_clockevent (p, name, clockevent_rating); +sh_tmu_register_clockevent (ch, name, clockevent_rating);else if (clocksource_rating) -sh_tmu_register_clocksource (p, name, clocksource_rating); +sh_tmu_register_clocksource (ch, name, clocksource_rating);return 0 ; }
@@ -445,8 +459,8 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) goto err0; } - p->irq =platform_get_irq (p->pdev,0 ); -if (p->irq <0 ) { + p->channel.irq =platform_get_irq (p->pdev,0 ); +if (p->channel.irq <0 ) {dev_err (&p->pdev->dev,"failed to get irq\n" ); goto err0; }
@@ -470,10 +484,11 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)if (ret <0 ) goto err2; - p->cs_enabled = false; - p->enable_count =0 ; + p->channel.cs_enabled = false; + p->channel.enable_count =0 ; + p->channel.tmu = p; - ret =sh_tmu_register (p, (char *)dev_name (&p->pdev->dev), + ret =sh_tmu_register (&p->channel, (char *)dev_name (&p->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating);if (ret <0 )
Signature · 1 line
1.7.9.5
PATCH 23/71 clocksource: sh_tmu: Rename struct sh_tmu_priv to sh_tmu_device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Channel data is private as well, rename priv to device to make the distrinction between the core device and the channels clearer.
--- drivers/clocksource/sh_tmu.c | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-)
drivers/clocksource/sh_tmu.c +34 -34
@@ -35,10 +35,10 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> -struct sh_tmu_priv ; +struct sh_tmu_device ;struct sh_tmu_channel { -struct sh_tmu_priv *tmu; +struct sh_tmu_device *tmu;int irq;
@@ -50,7 +50,7 @@ struct sh_tmu_channel {unsigned int enable_count; }; -struct sh_tmu_priv { +struct sh_tmu_device {struct platform_device *pdev;void __iomem *mapbase;
@@ -436,59 +436,59 @@ static int sh_tmu_register(struct sh_tmu_channel *ch, char *name,return 0 ; } -static int sh_tmu_setup (struct sh_tmu_priv *p,struct platform_device *pdev) +static int sh_tmu_setup (struct sh_tmu_device *tmu,struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res;int ret; ret = -ENXIO ; -memset (p,0 ,sizeof (*p)); - p->pdev = pdev; +memset (tmu,0 ,sizeof (*tmu)); + tmu->pdev = pdev;if (!cfg) { -dev_err (&p->pdev->dev,"missing platform data\n" ); +dev_err (&tmu->pdev->dev,"missing platform data\n" ); goto err0; } -platform_set_drvdata (pdev, p); +platform_set_drvdata (pdev, tmu); - res =platform_get_resource (p->pdev,IORESOURCE_MEM ,0 ); + res =platform_get_resource (tmu->pdev,IORESOURCE_MEM ,0 );if (!res) { -dev_err (&p->pdev->dev,"failed to get I/O memory\n" ); +dev_err (&tmu->pdev->dev,"failed to get I/O memory\n" ); goto err0; } - p->channel.irq =platform_get_irq (p->pdev,0 ); -if (p->channel.irq <0 ) { -dev_err (&p->pdev->dev,"failed to get irq\n" ); + tmu->channel.irq =platform_get_irq (tmu->pdev,0 ); +if (tmu->channel.irq <0 ) { +dev_err (&tmu->pdev->dev,"failed to get irq\n" ); goto err0; }/* map memory, let mapbase point to our channel */ - p->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (p->mapbase ==NULL ) { -dev_err (&p->pdev->dev,"failed to remap I/O memory\n" ); + tmu->mapbase =ioremap_nocache (res->start,resource_size (res)); +if (tmu->mapbase ==NULL ) { +dev_err (&tmu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; }/* get hold of clock */ - p->clk =clk_get (&p->pdev->dev,"tmu_fck" ); -if (IS_ERR (p->clk)) { -dev_err (&p->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (p->clk); + tmu->clk =clk_get (&tmu->pdev->dev,"tmu_fck" ); +if (IS_ERR (tmu->clk)) { +dev_err (&tmu->pdev->dev,"cannot get clock\n" ); + ret =PTR_ERR (tmu->clk); goto err1; } - ret =clk_prepare (p->clk); + ret =clk_prepare (tmu->clk);if (ret <0 ) goto err2; - p->channel.cs_enabled = false; - p->channel.enable_count =0 ; - p->channel.tmu = p; + tmu->channel.cs_enabled = false; + tmu->channel.enable_count =0 ; + tmu->channel.tmu = tmu; - ret =sh_tmu_register (&p->channel, (char *)dev_name (&p->pdev->dev), + ret =sh_tmu_register (&tmu->channel, (char *)dev_name (&tmu->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating);if (ret <0 )
@@ -497,18 +497,18 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)return 0 ; err3: -clk_unprepare (p->clk); +clk_unprepare (tmu->clk); err2: -clk_put (p->clk); +clk_put (tmu->clk); err1: -iounmap (p->mapbase); +iounmap (tmu->mapbase); err0:return ret; }static int sh_tmu_probe (struct platform_device *pdev) { -struct sh_tmu_priv *p =platform_get_drvdata (pdev); +struct sh_tmu_device *tmu =platform_get_drvdata (pdev);struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;
@@ -517,20 +517,20 @@ static int sh_tmu_probe(struct platform_device *pdev)pm_runtime_enable (&pdev->dev); } -if (p) { +if (tmu) {dev_info (&pdev->dev,"kept as earlytimer\n" ); goto out; } - p =kmalloc (sizeof (*p),GFP_KERNEL ); -if (p ==NULL ) { + tmu =kmalloc (sizeof (*tmu),GFP_KERNEL ); +if (tmu ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ; } - ret =sh_tmu_setup (p, pdev); + ret =sh_tmu_setup (tmu, pdev);if (ret) { -kfree (p); +kfree (tmu);pm_runtime_idle (&pdev->dev);return ret; }
Signature · 1 line
1.7.9.5
PATCH 24/71 clocksource: sh_tmu: Split channel setup to separate function
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Move the channel setup code from sh_tmu_setup to a new sh_tmu_setup_channel function and call it from sh_tmu_setup.
--- drivers/clocksource/sh_tmu.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-)
drivers/clocksource/sh_tmu.c +23 -13
@@ -436,6 +436,28 @@ static int sh_tmu_register(struct sh_tmu_channel *ch, char *name,return 0 ; } +static int sh_tmu_channel_setup (struct sh_tmu_channel *ch, +struct sh_tmu_device *tmu) +{ +struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; + +memset (ch,0 ,sizeof (*ch)); + ch->tmu = tmu; + + ch->irq =platform_get_irq (tmu->pdev,0 ); +if (ch->irq <0 ) { +dev_err (&tmu->pdev->dev,"failed to get irq\n" ); +return ch->irq; + } + + ch->cs_enabled = false; + ch->enable_count =0 ; + +return sh_tmu_register (ch, (char *)dev_name (&tmu->pdev->dev), + cfg->clockevent_rating, + cfg->clocksource_rating); +} +static int sh_tmu_setup (struct sh_tmu_device *tmu,struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -459,12 +481,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) goto err0; } - tmu->channel.irq =platform_get_irq (tmu->pdev,0 ); -if (tmu->channel.irq <0 ) { -dev_err (&tmu->pdev->dev,"failed to get irq\n" ); - goto err0; - } -/* map memory, let mapbase point to our channel */ tmu->mapbase =ioremap_nocache (res->start,resource_size (res));if (tmu->mapbase ==NULL ) {
@@ -484,13 +500,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)if (ret <0 ) goto err2; - tmu->channel.cs_enabled = false; - tmu->channel.enable_count =0 ; - tmu->channel.tmu = tmu; - - ret =sh_tmu_register (&tmu->channel, (char *)dev_name (&tmu->pdev->dev), - cfg->clockevent_rating, - cfg->clocksource_rating); + ret =sh_tmu_channel_setup (&tmu->channel, tmu);if (ret <0 ) goto err3;
Signature · 1 line
1.7.9.5
PATCH 25/71 clocksource: sh_tmu: Constify name argument to sh_tmu_register()
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The name argument is assigned to const structure fields only, constify it.
--- drivers/clocksource/sh_tmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/clocksource/sh_tmu.c +4 -4
@@ -292,7 +292,7 @@ static void sh_tmu_clocksource_resume(struct clocksource *cs) }static int sh_tmu_register_clocksource (struct sh_tmu_channel *ch, -char *name,unsigned long rating) +const char *name,unsigned long rating) {struct clocksource *cs = &ch->cs;
@@ -393,7 +393,7 @@ static void sh_tmu_clock_event_resume(struct clock_event_device *ced) }static void sh_tmu_register_clockevent (struct sh_tmu_channel *ch, -char *name,unsigned long rating) +const char *name,unsigned long rating) {struct clock_event_device *ced = &ch->ced;int ret;
@@ -424,7 +424,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, } } -static int sh_tmu_register (struct sh_tmu_channel *ch,char *name, +static int sh_tmu_register (struct sh_tmu_channel *ch,const char *name,unsigned long clockevent_rating,unsigned long clocksource_rating) {
@@ -453,7 +453,7 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, ch->cs_enabled = false; ch->enable_count =0 ; -return sh_tmu_register (ch, (char *)dev_name (&tmu->pdev->dev), +return sh_tmu_register (ch,dev_name (&tmu->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating); }
Signature · 1 line
1.7.9.5
PATCH 26/71 clocksource: sh_tmu: Add memory base to sh_tmu_channel structure
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The channel memory base is channel-specific, add it to the channel structure in preparation for support of multiple channels per device.
--- drivers/clocksource/sh_tmu.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-)
drivers/clocksource/sh_tmu.c +16 -14
@@ -40,6 +40,7 @@ struct sh_tmu_device;struct sh_tmu_channel {struct sh_tmu_device *tmu; +void __iomem *base;int irq;unsigned long rate;
@@ -68,39 +69,35 @@ static DEFINE_RAW_SPINLOCK(sh_tmu_lock);static inline unsigned long sh_tmu_read (struct sh_tmu_channel *ch,int reg_nr) { -struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data; -void __iomem *base = ch->tmu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) -return ioread8 (base - cfg->channel_offset); +return ioread8 (ch->tmu->mapbase); offs = reg_nr <<2 ;if (reg_nr ==TCR ) -return ioread16 (base + offs); +return ioread16 (ch->base + offs);else -return ioread32 (base + offs); +return ioread32 (ch->base + offs); }static inline void sh_tmu_write (struct sh_tmu_channel *ch,int reg_nr,unsigned long value) { -struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data; -void __iomem *base = ch->tmu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) { -iowrite8 (value, base - cfg->channel_offset); +iowrite8 (value, ch->tmu->mapbase);return ; } offs = reg_nr <<2 ;if (reg_nr ==TCR ) -iowrite16 (value, base + offs); +iowrite16 (value, ch->base + offs);else -iowrite32 (value, base + offs); +iowrite32 (value, ch->base + offs); }static void sh_tmu_start_stop_ch (struct sh_tmu_channel *ch,int start)
@@ -481,13 +478,18 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) goto err0; } -/* map memory, let mapbase point to our channel */ - tmu->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (tmu->mapbase ==NULL ) { +/* +* Map memory, let channel.base point to our channel and mapbase to the +* start/stop shared register. +*/ + tmu->channel.base =ioremap_nocache (res->start,resource_size (res)); +if (tmu->channel.base ==NULL ) {dev_err (&tmu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; } + tmu->mapbase = tmu->channel.base - cfg->channel_offset; +/* get hold of clock */ tmu->clk =clk_get (&tmu->pdev->dev,"tmu_fck" );if (IS_ERR (tmu->clk)) {
@@ -511,7 +513,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) err2:clk_put (tmu->clk); err1: -iounmap (tmu->mapbase); +iounmap (tmu->channel.base); err0:return ret; }
Signature · 1 line
1.7.9.5
PATCH 27/71 clocksource: sh_tmu: Add index to struct sh_tmu_channel
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Use the index as the timer start/stop bit and when printing messages to identify the channel.
--- drivers/clocksource/sh_tmu.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-)
drivers/clocksource/sh_tmu.c +24 -11
@@ -39,6 +39,7 @@ struct sh_tmu_device;struct sh_tmu_channel {struct sh_tmu_device *tmu; +unsigned int index;void __iomem *base;int irq;
@@ -102,7 +103,6 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr,static void sh_tmu_start_stop_ch (struct sh_tmu_channel *ch,int start) { -struct sh_timer_config *cfg = ch->tmu->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */
@@ -110,9 +110,9 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) value =sh_tmu_read (ch,TSTR );if (start) - value |=1 << cfg->timer_bit; + value |=1 << ch->index;else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << ch->index);sh_tmu_write (ch,TSTR , value);raw_spin_unlock_irqrestore (&sh_tmu_lock, flags);
@@ -125,7 +125,8 @@ static int __sh_tmu_enable(struct sh_tmu_channel *ch)/* enable clock */ ret =clk_enable (ch->tmu->clk);if (ret) { -dev_err (&ch->tmu->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->tmu->pdev->dev,"ch%u: cannot enable clock\n" , + ch->index);return ret; }
@@ -303,7 +304,8 @@ static int sh_tmu_register_clocksource(struct sh_tmu_channel *ch, cs->mask =CLOCKSOURCE_MASK (32 ); cs->flags =CLOCK_SOURCE_IS_CONTINUOUS ; -dev_info (&ch->tmu->pdev->dev,"used as clock source\n" ); +dev_info (&ch->tmu->pdev->dev,"ch%u: used as clock source\n" , + ch->index);/* Register with dummy 1 Hz value, gets updated in ->enable() */ clocksource_register_hz (cs,1 );
@@ -349,12 +351,12 @@ static void sh_tmu_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC :dev_info (&ch->tmu->pdev->dev, -"used for periodic clock events\n" ); +"ch%u: used for periodic clock events\n" , ch->index);sh_tmu_clock_event_start (ch,1 );break ;case CLOCK_EVT_MODE_ONESHOT :dev_info (&ch->tmu->pdev->dev, -"used for oneshot clock events\n" ); +"ch%u: used for oneshot clock events\n" , ch->index);sh_tmu_clock_event_start (ch,0 );break ;case CLOCK_EVT_MODE_UNUSED :
@@ -407,7 +409,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ced->suspend = sh_tmu_clock_event_suspend; ced->resume = sh_tmu_clock_event_resume; -dev_info (&ch->tmu->pdev->dev,"used for clock events\n" ); +dev_info (&ch->tmu->pdev->dev,"ch%u: used for clock events\n" , + ch->index);clockevents_config_and_register (ced,1 ,0x300 ,0xffffffff );
@@ -415,8 +418,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , dev_name(&ch->tmu->pdev->dev), ch);if (ret) { -dev_err (&ch->tmu->pdev->dev,"failed to request irq %d\n" , - ch->irq); +dev_err (&ch->tmu->pdev->dev,"ch%u: failed to request irq %d\n" , + ch->index, ch->irq);return ; } }
@@ -441,9 +444,19 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch,memset (ch,0 ,sizeof (*ch)); ch->tmu = tmu; +/* +* The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps channel +* registers blocks at base + 2 + 12 * index, while all other variants +* map them at base + 4 + 12 * index. We can compute the index by just +* dividing by 12, the 2 bytes or 4 bytes offset being hidden by the +* integer division. +*/ + ch->index = cfg->channel_offset /12 ; + ch->irq =platform_get_irq (tmu->pdev,0 );if (ch->irq <0 ) { -dev_err (&tmu->pdev->dev,"failed to get irq\n" ); +dev_err (&tmu->pdev->dev,"ch%u: failed to get irq\n" , + ch->index);return ch->irq; }
Signature · 1 line
1.7.9.5
PATCH 28/71 clocksource: sh_tmu: Replace kmalloc + memset with kzalloc
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
One kzalloc a day keeps the bugs away.
--- drivers/clocksource/sh_tmu.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/clocksource/sh_tmu.c +1 -5
@@ -397,8 +397,6 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,struct clock_event_device *ced = &ch->ced;int ret; -memset (ced,0 ,sizeof (*ced)); - ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->features |=CLOCK_EVT_FEAT_ONESHOT ;
@@ -441,7 +439,6 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, {struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; -memset (ch,0 ,sizeof (*ch)); ch->tmu = tmu;/*
@@ -475,7 +472,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)int ret; ret = -ENXIO ; -memset (tmu,0 ,sizeof (*tmu)); tmu->pdev = pdev;if (!cfg) {
@@ -547,7 +543,7 @@ static int sh_tmu_probe(struct platform_device *pdev) goto out; } - tmu =kmalloc (sizeof (*tmu),GFP_KERNEL ); + tmu =kzalloc (sizeof (*tmu),GFP_KERNEL );if (tmu ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ;
Signature · 1 line
1.7.9.5
PATCH 29/71 clocksource: sh_tmu: Allocate channels dynamically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This prepares the driver for multi-channel support.
--- drivers/clocksource/sh_tmu.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
drivers/clocksource/sh_tmu.c +20 -7
@@ -58,7 +58,8 @@ struct sh_tmu_device {void __iomem *mapbase;struct clk *clk; -struct sh_tmu_channel channel; +struct sh_tmu_channel *channels; +unsigned int num_channels; };static DEFINE_RAW_SPINLOCK (sh_tmu_lock);
@@ -469,6 +470,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; +void __iomem *base;int ret; ret = -ENXIO ;
@@ -488,16 +490,16 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) }/* -* Map memory, let channel.base point to our channel and mapbase to the +* Map memory, let base point to our channel and mapbase to the * start/stop shared register. */ - tmu->channel.base =ioremap_nocache (res->start,resource_size (res)); -if (tmu->channel.base ==NULL ) { + base =ioremap_nocache (res->start,resource_size (res)); +if (base ==NULL ) {dev_err (&tmu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; } - tmu->mapbase = tmu->channel.base - cfg->channel_offset; + tmu->mapbase = base - cfg->channel_offset;/* get hold of clock */ tmu->clk =clk_get (&tmu->pdev->dev,"tmu_fck" );
@@ -511,18 +513,29 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)if (ret <0 ) goto err2; - ret =sh_tmu_channel_setup (&tmu->channel, tmu); + tmu->channels =kzalloc (sizeof (*tmu->channels),GFP_KERNEL ); +if (tmu->channels ==NULL ) { + ret = -ENOMEM ; + goto err3; + } + + tmu->num_channels =1 ; + + tmu->channels[0 ].base = base; + + ret =sh_tmu_channel_setup (&tmu->channels[0 ], tmu);if (ret <0 ) goto err3;return 0 ; err3: +kfree (tmu->channels);clk_unprepare (tmu->clk); err2:clk_put (tmu->clk); err1: -iounmap (tmu->channel.base); +iounmap (base); err0:return ret; }
Signature · 1 line
1.7.9.5
PATCH 30/71 clocksource: sh_tmu: Replace hardcoded register values with macros
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Define symbolic macros for all used registers bits.
--- drivers/clocksource/sh_tmu.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/clocksource/sh_tmu.c +14 -5
@@ -69,6 +69,15 @@ static DEFINE_RAW_SPINLOCK(sh_tmu_lock);#define TCNT 1/* channel register */ #define TCR 2/* channel register */ +#define TCR_UNF (1 << 8) +#define TCR_UNIE (1 << 5) +#define TCR_TPSC_CLK4 (0 << 0) +#define TCR_TPSC_CLK16 (1 << 0) +#define TCR_TPSC_CLK64 (2 << 0) +#define TCR_TPSC_CLK256 (3 << 0) +#define TCR_TPSC_CLK1024 (4 << 0) +#define TCR_TPSC_MASK (7 << 0) +static inline unsigned long sh_tmu_read (struct sh_tmu_channel *ch,int reg_nr) {unsigned long offs;
@@ -140,7 +149,7 @@ static int __sh_tmu_enable(struct sh_tmu_channel *ch)/* configure channel to parent clock / 4, irq off */ ch->rate =clk_get_rate (ch->tmu->clk) /4 ; -sh_tmu_write (ch,TCR ,0x0000 ); +sh_tmu_write (ch,TCR ,TCR_TPSC_CLK4 );/* enable channel */ sh_tmu_start_stop_ch (ch,1 );
@@ -165,7 +174,7 @@ static void __sh_tmu_disable(struct sh_tmu_channel *ch)sh_tmu_start_stop_ch (ch,0 );/* disable interrupts in TMU block */ -sh_tmu_write (ch,TCR ,0x0000 ); +sh_tmu_write (ch,TCR ,TCR_TPSC_CLK4 );/* stop clock */ clk_disable (ch->tmu->clk);
@@ -195,7 +204,7 @@ static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta,sh_tmu_read (ch,TCR );/* enable interrupt */ -sh_tmu_write (ch,TCR ,0x0020 ); +sh_tmu_write (ch,TCR ,TCR_UNIE |TCR_TPSC_CLK4 );/* reload delta value in case of periodic timer */ if (periodic)
@@ -215,9 +224,9 @@ static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)/* disable or acknowledge interrupt */ if (ch->ced.mode ==CLOCK_EVT_MODE_ONESHOT ) -sh_tmu_write (ch,TCR ,0x0000 ); +sh_tmu_write (ch,TCR ,TCR_TPSC_CLK4 );else -sh_tmu_write (ch,TCR ,0x0020 ); +sh_tmu_write (ch,TCR ,TCR_UNIE |TCR_TPSC_CLK4 );/* notify clockevent layer */ ch->ced.event_handler (&ch->ced);
Signature · 1 line
1.7.9.5
PATCH 31/71 clocksource: sh_tmu: Hardcode TMU clock event and source ratings to 200
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
All boards use clock event and clock source ratings of 200 for the TMU, hardcode it in the driver.
--- drivers/clocksource/sh_tmu.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)
drivers/clocksource/sh_tmu.c +11 -12
@@ -300,12 +300,12 @@ static void sh_tmu_clocksource_resume(struct clocksource *cs) }static int sh_tmu_register_clocksource (struct sh_tmu_channel *ch, -const char *name,unsigned long rating) +const char *name) {struct clocksource *cs = &ch->cs; cs->name = name; - cs->rating = rating; + cs->rating =200 ; cs->read = sh_tmu_clocksource_read; cs->enable = sh_tmu_clocksource_enable; cs->disable = sh_tmu_clocksource_disable;
@@ -402,7 +402,7 @@ static void sh_tmu_clock_event_resume(struct clock_event_device *ced) }static void sh_tmu_register_clockevent (struct sh_tmu_channel *ch, -const char *name,unsigned long rating) +const char *name) {struct clock_event_device *ced = &ch->ced;int ret;
@@ -410,7 +410,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->features |=CLOCK_EVT_FEAT_ONESHOT ; - ced->rating = rating; + ced->rating =200 ; ced->cpumask =cpumask_of (0 ); ced->set_next_event = sh_tmu_clock_event_next; ced->set_mode = sh_tmu_clock_event_mode;
@@ -433,13 +433,12 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, }static int sh_tmu_register (struct sh_tmu_channel *ch,const char *name, -unsigned long clockevent_rating, -unsigned long clocksource_rating) +bool clockevent,bool clocksource) { -if (clockevent_rating) -sh_tmu_register_clockevent (ch, name, clockevent_rating); -else if (clocksource_rating) -sh_tmu_register_clocksource (ch, name, clocksource_rating); +if (clockevent) +sh_tmu_register_clockevent (ch, name); +else if (clocksource) +sh_tmu_register_clocksource (ch, name);return 0 ; }
@@ -471,8 +470,8 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, ch->enable_count =0 ;return sh_tmu_register (ch,dev_name (&tmu->pdev->dev), - cfg->clockevent_rating, - cfg->clocksource_rating); + cfg->clockevent_rating !=0 , + cfg->clocksource_rating !=0 ); }static int sh_tmu_setup (struct sh_tmu_device *tmu,struct platform_device *pdev)
Signature · 1 line
1.7.9.5
PATCH 32/71 clocksource: sh_tmu: Add support for multiple channels per device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
TMU hardware devices can support multiple channels, with global registers and per-channel registers. The sh_tmu driver currently models the hardware with one Linux device per channel. This model makes it difficult to handle global registers in a clean way.
Add support for a new model that uses one Linux device per timer with multiple channels per device. This requires changes to platform data, add new channel configuration fields.
Support for the legacy model is kept and will be removed after all platforms switch to the new model.
--- drivers/clocksource/sh_tmu.c | 213 ++++++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 61 deletions(-)
drivers/clocksource/sh_tmu.c +152 -61
@@ -35,6 +35,12 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> +enum sh_tmu_model { +SH_TMU_LEGACY , +SH_TMU , +SH_TMU_SH3 , +}; +struct sh_tmu_device ;struct sh_tmu_channel {
@@ -58,8 +64,13 @@ struct sh_tmu_device {void __iomem *mapbase;struct clk *clk; +enum sh_tmu_model model; +struct sh_tmu_channel *channels;unsigned int num_channels; + +bool has_clockevent; +bool has_clocksource; };static DEFINE_RAW_SPINLOCK (sh_tmu_lock);
@@ -82,8 +93,16 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_channel *ch, int reg_nr) {unsigned long offs; -if (reg_nr ==TSTR ) -return ioread8 (ch->tmu->mapbase); +if (reg_nr ==TSTR ) { +switch (ch->tmu->model) { +case SH_TMU_LEGACY : +return ioread8 (ch->tmu->mapbase); +case SH_TMU_SH3 : +return ioread8 (ch->tmu->mapbase +2 ); +case SH_TMU : +return ioread8 (ch->tmu->mapbase +4 ); + } + } offs = reg_nr <<2 ;
@@ -99,8 +118,14 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr,unsigned long offs;if (reg_nr ==TSTR ) { -iowrite8 (value, ch->tmu->mapbase); -return ; +switch (ch->tmu->model) { +case SH_TMU_LEGACY : +return iowrite8 (value, ch->tmu->mapbase); +case SH_TMU_SH3 : +return iowrite8 (value, ch->tmu->mapbase +2 ); +case SH_TMU : +return iowrite8 (value, ch->tmu->mapbase +4 ); + } } offs = reg_nr <<2 ;
@@ -435,31 +460,49 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,static int sh_tmu_register (struct sh_tmu_channel *ch,const char *name,bool clockevent,bool clocksource) { -if (clockevent) +if (clockevent) { + ch->tmu->has_clockevent = true;sh_tmu_register_clockevent (ch, name); -else if (clocksource) + }else if (clocksource) { + ch->tmu->has_clocksource = true;sh_tmu_register_clocksource (ch, name); + }return 0 ; } -static int sh_tmu_channel_setup (struct sh_tmu_channel *ch, +static int sh_tmu_channel_setup (struct sh_tmu_channel *ch,unsigned int index, +bool clockevent,bool clocksource,struct sh_tmu_device *tmu) { -struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; +/* Skip unused channels. */ +if (!clockevent && !clocksource) +return 0 ; ch->tmu = tmu; -/* -* The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps channel -* registers blocks at base + 2 + 12 * index, while all other variants -* map them at base + 4 + 12 * index. We can compute the index by just -* dividing by 12, the 2 bytes or 4 bytes offset being hidden by the -* integer division. -*/ - ch->index = cfg->channel_offset /12 ; +if (tmu->model ==SH_TMU_LEGACY ) { +struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; + +/* +* The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps +* channel registers blocks at base + 2 + 12 * index, while all +* other variants map them at base + 4 + 12 * index. We can +* compute the index by just dividing by 12, the 2 bytes or 4 +* bytes offset being hidden by the integer division. +*/ + ch->index = cfg->channel_offset /12 ; + ch->base = tmu->mapbase + cfg->channel_offset; + }else { + ch->index = index; + +if (tmu->model ==SH_TMU_SH3 ) + ch->base = tmu->mapbase +4 + ch->index *12 ; +else + ch->base = tmu->mapbase +8 + ch->index *12 ; + } - ch->irq =platform_get_irq (tmu->pdev,0 ); + ch->irq =platform_get_irq (tmu->pdev, ch->index);if (ch->irq <0 ) {dev_err (&tmu->pdev->dev,"ch%u: failed to get irq\n" , ch->index);
@@ -470,88 +513,127 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, ch->enable_count =0 ;return sh_tmu_register (ch,dev_name (&tmu->pdev->dev), - cfg->clockevent_rating !=0 , - cfg->clocksource_rating !=0 ); + clockevent, clocksource); } -static int sh_tmu_setup (struct sh_tmu_device *tmu,struct platform_device *pdev) +static int sh_tmu_map_memory (struct sh_tmu_device *tmu) { -struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; -void __iomem *base; -int ret; - ret = -ENXIO ; - - tmu->pdev = pdev; - -if (!cfg) { -dev_err (&tmu->pdev->dev,"missing platform data\n" ); - goto err0; - } - -platform_set_drvdata (pdev, tmu); res =platform_get_resource (tmu->pdev,IORESOURCE_MEM ,0 );if (!res) {dev_err (&tmu->pdev->dev,"failed to get I/O memory\n" ); - goto err0; +return -ENXIO ; } + tmu->mapbase =ioremap_nocache (res->start,resource_size (res)); +if (tmu->mapbase ==NULL ) +return -ENXIO ; +/* -* Map memory, let base point to our channel and mapbase to the -* start/stop shared register. +* In legacy platform device configuration (with one device per channel) +* the resource points to the channel base address. */ - base =ioremap_nocache (res->start,resource_size (res)); -if (base ==NULL ) { -dev_err (&tmu->pdev->dev,"failed to remap I/O memory\n" ); - goto err0; +if (tmu->model ==SH_TMU_LEGACY ) { +struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; + tmu->mapbase -= cfg->channel_offset; } - tmu->mapbase = base - cfg->channel_offset; +return 0 ; +} -/* get hold of clock */ +static void sh_tmu_unmap_memory (struct sh_tmu_device *tmu) +{ +if (tmu->model ==SH_TMU_LEGACY ) { +struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; + tmu->mapbase += cfg->channel_offset; + } + +iounmap (tmu->mapbase); +} + +static int sh_tmu_setup (struct sh_tmu_device *tmu,struct platform_device *pdev) +{ +struct sh_timer_config *cfg = pdev->dev.platform_data; +const struct platform_device_id *id = pdev->id_entry; +unsigned int i; +int ret; + +if (!cfg) { +dev_err (&tmu->pdev->dev,"missing platform data\n" ); +return -ENXIO ; + } + + tmu->pdev = pdev; + tmu->model = id->driver_data; + +/* Get hold of clock. */ tmu->clk =clk_get (&tmu->pdev->dev,"tmu_fck" );if (IS_ERR (tmu->clk)) {dev_err (&tmu->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (tmu->clk); - goto err1; +return PTR_ERR (tmu->clk); } ret =clk_prepare (tmu->clk);if (ret <0 ) - goto err2; + goto err_clk_put; + +/* Map the memory resource. */ + ret =sh_tmu_map_memory (tmu); +if (ret <0 ) { +dev_err (&tmu->pdev->dev,"failed to remap I/O memory\n" ); + goto err_clk_unprepare; + } - tmu->channels =kzalloc (sizeof (*tmu->channels),GFP_KERNEL ); +/* Allocate and setup the channels. */ +if (tmu->model ==SH_TMU_LEGACY ) + tmu->num_channels =1 ; +else + tmu->num_channels =hweight8 (cfg->channels_mask); + + tmu->channels =kzalloc (sizeof (*tmu->channels) * tmu->num_channels, +GFP_KERNEL );if (tmu->channels ==NULL ) { ret = -ENOMEM ; - goto err3; + goto err_unmap; } - tmu->num_channels =1 ; - - tmu->channels[0 ].base = base; +if (tmu->model ==SH_TMU_LEGACY ) { + ret =sh_tmu_channel_setup (&tmu->channels[0 ],0 , + cfg->clockevent_rating !=0 , + cfg->clocksource_rating !=0 , tmu); +if (ret <0 ) + goto err_unmap; + }else { +/* +* Use the first channel as a clock event device and the second +* channel as a clock source. +*/ +for (i =0 ; i < tmu->num_channels; ++i) { + ret =sh_tmu_channel_setup (&tmu->channels[i], i, + i ==0 , i ==1 , tmu); +if (ret <0 ) + goto err_unmap; + } + } - ret =sh_tmu_channel_setup (&tmu->channels[0 ], tmu); -if (ret <0 ) - goto err3; +platform_set_drvdata (pdev, tmu);return 0 ; - err3: +err_unmap:kfree (tmu->channels); +sh_tmu_unmap_memory (tmu); +err_clk_unprepare:clk_unprepare (tmu->clk); - err2: +err_clk_put:clk_put (tmu->clk); - err1: -iounmap (base); - err0:return ret; }static int sh_tmu_probe (struct platform_device *pdev) {struct sh_tmu_device *tmu =platform_get_drvdata (pdev); -struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;if (!is_early_platform_device (pdev)) {
@@ -580,7 +662,7 @@ static int sh_tmu_probe(struct platform_device *pdev)return 0 ; out: -if (cfg->clockevent_rating || cfg->clocksource_rating) +if (tmu->has_clockevent || tmu->has_clocksource)pm_runtime_irq_safe (&pdev->dev);else pm_runtime_idle (&pdev->dev);
@@ -593,12 +675,21 @@ static int sh_tmu_remove(struct platform_device *pdev)return -EBUSY ;/* cannot unregister clockevent and clocksource */ } +static const struct platform_device_id sh_tmu_id_table[] = { + {"sh_tmu" ,SH_TMU_LEGACY }, + {"sh-tmu" ,SH_TMU }, + {"sh-tmu-sh3" ,SH_TMU_SH3 }, + { } +}; +MODULE_DEVICE_TABLE (platform, sh_tmu_id_table); +static struct platform_driver sh_tmu_device_driver = { .probe = sh_tmu_probe, .remove = sh_tmu_remove, .driver = { .name ="sh_tmu" , - } + }, + .id_table = sh_tmu_id_table, };static int __init sh_tmu_init (void )
Signature · 1 line
1.7.9.5
PATCH 33/71 clocksource: sh_tmu: Rename clock to "fck" in the non-legacy case
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The sh_tmu driver gets the TMU functional clock using a connection ID of "tmu_fck". While all SH SoCs create clock lookup entries with a NULL device ID and a "tmu_fck" connection ID, the ARM SoCs use the device ID only with a NULL connection ID. This works on legacy platforms but will break on ARM with DT boot.
Fix the situation by using a connection ID of "fck" in the non-legacy platform data case. Clock lookup entries will be renamed to use the device ID as well as the connection ID as platforms get moved to new platform data. The legacy code will eventually be dropped, leaving us with device ID based clock lookup, compatible with DT boot.
--- drivers/clocksource/sh_tmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/clocksource/sh_tmu.c +2 -1
@@ -568,7 +568,8 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) tmu->model = id->driver_data;/* Get hold of clock. */ - tmu->clk =clk_get (&tmu->pdev->dev,"tmu_fck" ); + tmu->clk =clk_get (&tmu->pdev->dev, + tmu->model ==SH_TMU_LEGACY ?"tmu_fck" :"fck" );if (IS_ERR (tmu->clk)) {dev_err (&tmu->pdev->dev,"cannot get clock\n" );return PTR_ERR (tmu->clk);
Signature · 1 line
1.7.9.5
PATCH 34/71 clocksource: sh_tmu: Remove FSF mail address from GPL notice
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
--- drivers/clocksource/sh_tmu.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/clocksource/sh_tmu.c +0 -4
@@ -11,10 +11,6 @@* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h>
Signature · 1 line
1.7.9.5
PATCH 35/71 clocksource: sh_tmu: Sort headers alphabetically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This helps locating duplicates and inserting new headers.
--- drivers/clocksource/sh_tmu.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
drivers/clocksource/sh_tmu.c +10 -10
@@ -13,23 +13,23 @@* GNU General Public License for more details. */ +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/delay.h> #include <linux/io.h> -#include <linux/clk.h> +#include <linux/ioport.h> #include <linux/irq.h> -#include <linux/err.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/sh_timer.h> -#include <linux/slab.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/sh_timer.h> +#include <linux/slab.h> +#include <linux/spinlock.h> enum sh_tmu_model {SH_TMU_LEGACY ,
Signature · 1 line
1.7.9.5
PATCH 36/71 clocksource: sh_mtu2: Use request_irq() instead of setup_irq()
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The driver claims it needs to register an interrupt handler too early for request_irq(). This might have been true in the past, but the only meaningful difference between request_irq() and setup_irq() today is an additional kzalloc() call in request_irq(). As the driver calls kmalloc() itself we know that the slab allocator is available, we can thus switch to request_irq().
--- drivers/clocksource/sh_mtu2.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-)
drivers/clocksource/sh_mtu2.c +8 -14
@@ -37,7 +37,7 @@struct sh_mtu2_priv {void __iomem *mapbase;struct clk *clk; -struct irqaction irqaction; +int irq;struct platform_device *pdev;unsigned long rate;unsigned long periodic;
@@ -244,10 +244,11 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,dev_info (&p->pdev->dev,"used for clock events\n" );clockevents_register_device (ced); - ret =setup_irq (p->irqaction.irq, &p->irqaction); + ret =request_irq (p->irq, sh_mtu2_interrupt, +IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , +dev_name (&p->pdev->dev), p);if (ret) { -dev_err (&p->pdev->dev,"failed to request irq %d\n" , - p->irqaction.irq); +dev_err (&p->pdev->dev,"failed to request irq %d\n" , p->irq);return ; } }
@@ -265,7 +266,7 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; -int irq, ret; +int ret; ret = -ENXIO ;memset (p,0 ,sizeof (*p));
@@ -284,8 +285,8 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) goto err0; } - irq =platform_get_irq (p->pdev,0 ); -if (irq <0 ) { + p->irq =platform_get_irq (p->pdev,0 ); +if (p->irq <0 ) {dev_err (&p->pdev->dev,"failed to get irq\n" ); goto err0; }
@@ -297,13 +298,6 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) goto err0; } -/* setup data for setup_irq() (too early for request_irq()) */ - p->irqaction.name =dev_name (&p->pdev->dev); - p->irqaction.handler = sh_mtu2_interrupt; - p->irqaction.dev_id = p; - p->irqaction.irq = irq; - p->irqaction.flags =IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING ; -/* get hold of clock */ p->clk =clk_get (&p->pdev->dev,"mtu2_fck" );if (IS_ERR (p->clk)) {
Signature · 1 line
1.7.9.5
PATCH 37/71 clocksource: sh_mtu2: Turn sh_mtu2_priv fields into local variables
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The rate and periodic fields are used in a single function only, as local variables. Remove them from the structure.
--- drivers/clocksource/sh_mtu2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/clocksource/sh_mtu2.c +5 -5
@@ -39,8 +39,6 @@ struct sh_mtu2_priv {struct clk *clk;int irq;struct platform_device *pdev; -unsigned long rate; -unsigned long periodic;struct clock_event_device ced; };
@@ -122,6 +120,8 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start)static int sh_mtu2_enable (struct sh_mtu2_priv *p) { +unsigned long periodic; +unsigned long rate;int ret;pm_runtime_get_sync (&p->pdev->dev);
@@ -137,13 +137,13 @@ static int sh_mtu2_enable(struct sh_mtu2_priv *p)/* make sure channel is disabled */ sh_mtu2_start_stop_ch (p,0 ); - p->rate =clk_get_rate (p->clk) /64 ; - p->periodic = (p->rate +HZ /2 ) /HZ ; + rate =clk_get_rate (p->clk) /64 ; + periodic = (rate +HZ /2 ) /HZ ;/* "Periodic Counter Operation" */ sh_mtu2_write (p,TCR ,0x23 );/* TGRA clear, divide clock by 64 */ sh_mtu2_write (p,TIOR ,0 ); -sh_mtu2_write (p,TGR , p->periodic); +sh_mtu2_write (p,TGR , periodic);sh_mtu2_write (p,TCNT ,0 );sh_mtu2_write (p,TMDR ,0 );sh_mtu2_write (p,TIER ,0x01 );
Signature · 1 line
1.7.9.5
PATCH 38/71 clocksource: sh_mtu2: Split channel fields from sh_mtu2_priv
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Create a new sh_mtu2_channel structure to hold the channel-specific fields in preparation for multiple channels per device support.
--- drivers/clocksource/sh_mtu2.c | 125 +++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 56 deletions(-)
drivers/clocksource/sh_mtu2.c +69 -56
@@ -34,12 +34,21 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> +struct sh_mtu2_priv ; + +struct sh_mtu2_channel { +struct sh_mtu2_priv *mtu; +int irq; +struct clock_event_device ced; +}; +struct sh_mtu2_priv { +struct platform_device *pdev; +void __iomem *mapbase;struct clk *clk; -int irq; -struct platform_device *pdev; -struct clock_event_device ced; + +struct sh_mtu2_channel channel; };static DEFINE_RAW_SPINLOCK (sh_mtu2_lock);
@@ -63,10 +72,10 @@ static unsigned long mtu2_reg_offs[] = { [TGR] = 8, }; -static inline unsigned long sh_mtu2_read (struct sh_mtu2_priv *p,int reg_nr) +static inline unsigned long sh_mtu2_read (struct sh_mtu2_channel *ch,int reg_nr) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; -void __iomem *base = p->mapbase; +struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data; +void __iomem *base = ch->mtu->mapbase;unsigned long offs;if (reg_nr ==TSTR )
@@ -80,11 +89,11 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr)return ioread8 (base + offs); } -static inline void sh_mtu2_write (struct sh_mtu2_priv *p,int reg_nr, +static inline void sh_mtu2_write (struct sh_mtu2_channel *ch,int reg_nr,unsigned long value) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; -void __iomem *base = p->mapbase; +struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data; +void __iomem *base = ch->mtu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) {
@@ -100,100 +109,100 @@ static inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr,iowrite8 (value, base + offs); } -static void sh_mtu2_start_stop_ch (struct sh_mtu2_priv *p,int start) +static void sh_mtu2_start_stop_ch (struct sh_mtu2_channel *ch,int start) { -struct sh_timer_config *cfg = p->pdev->dev.platform_data; +struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */ raw_spin_lock_irqsave (&sh_mtu2_lock, flags); - value =sh_mtu2_read (p,TSTR ); + value =sh_mtu2_read (ch,TSTR );if (start) value |=1 << cfg->timer_bit;else value &= ~(1 << cfg->timer_bit); -sh_mtu2_write (p,TSTR , value); +sh_mtu2_write (ch,TSTR , value);raw_spin_unlock_irqrestore (&sh_mtu2_lock, flags); } -static int sh_mtu2_enable (struct sh_mtu2_priv *p) +static int sh_mtu2_enable (struct sh_mtu2_channel *ch) {unsigned long periodic;unsigned long rate;int ret; -pm_runtime_get_sync (&p->pdev->dev); -dev_pm_syscore_device (&p->pdev->dev, true); +pm_runtime_get_sync (&ch->mtu->pdev->dev); +dev_pm_syscore_device (&ch->mtu->pdev->dev, true);/* enable clock */ - ret =clk_enable (p->clk); + ret =clk_enable (ch->mtu->clk);if (ret) { -dev_err (&p->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->mtu->pdev->dev,"cannot enable clock\n" );return ret; }/* make sure channel is disabled */ -sh_mtu2_start_stop_ch (p,0 ); +sh_mtu2_start_stop_ch (ch,0 ); - rate =clk_get_rate (p->clk) /64 ; + rate =clk_get_rate (ch->mtu->clk) /64 ; periodic = (rate +HZ /2 ) /HZ ;/* "Periodic Counter Operation" */ -sh_mtu2_write (p,TCR ,0x23 );/* TGRA clear, divide clock by 64 */ -sh_mtu2_write (p,TIOR ,0 ); -sh_mtu2_write (p,TGR , periodic); -sh_mtu2_write (p,TCNT ,0 ); -sh_mtu2_write (p,TMDR ,0 ); -sh_mtu2_write (p,TIER ,0x01 ); +sh_mtu2_write (ch,TCR ,0x23 );/* TGRA clear, divide clock by 64 */ +sh_mtu2_write (ch,TIOR ,0 ); +sh_mtu2_write (ch,TGR , periodic); +sh_mtu2_write (ch,TCNT ,0 ); +sh_mtu2_write (ch,TMDR ,0 ); +sh_mtu2_write (ch,TIER ,0x01 );/* enable channel */ -sh_mtu2_start_stop_ch (p,1 ); +sh_mtu2_start_stop_ch (ch,1 );return 0 ; } -static void sh_mtu2_disable (struct sh_mtu2_priv *p) +static void sh_mtu2_disable (struct sh_mtu2_channel *ch) {/* disable channel */ -sh_mtu2_start_stop_ch (p,0 ); +sh_mtu2_start_stop_ch (ch,0 );/* stop clock */ -clk_disable (p->clk); +clk_disable (ch->mtu->clk); -dev_pm_syscore_device (&p->pdev->dev, false); -pm_runtime_put (&p->pdev->dev); +dev_pm_syscore_device (&ch->mtu->pdev->dev, false); +pm_runtime_put (&ch->mtu->pdev->dev); }static irqreturn_t sh_mtu2_interrupt (int irq,void *dev_id) { -struct sh_mtu2_priv *p = dev_id; +struct sh_mtu2_channel *ch = dev_id;/* acknowledge interrupt */ -sh_mtu2_read (p,TSR ); -sh_mtu2_write (p,TSR ,0xfe ); +sh_mtu2_read (ch,TSR ); +sh_mtu2_write (ch,TSR ,0xfe );/* notify clockevent layer */ - p->ced.event_handler (&p->ced); + ch->ced.event_handler (&ch->ced);return IRQ_HANDLED ; } -static struct sh_mtu2_priv *ced_to_sh_mtu2 (struct clock_event_device *ced) +static struct sh_mtu2_channel *ced_to_sh_mtu2 (struct clock_event_device *ced) { - return container_of(ced, struct sh_mtu2_priv, ced); + return container_of(ced, struct sh_mtu2_channel, ced); }static void sh_mtu2_clock_event_mode (enum clock_event_mode mode,struct clock_event_device *ced) { -struct sh_mtu2_priv *p =ced_to_sh_mtu2 (ced); +struct sh_mtu2_channel *ch =ced_to_sh_mtu2 (ced);int disabled =0 ;/* deal with old setting first */ switch (ced->mode) {case CLOCK_EVT_MODE_PERIODIC : -sh_mtu2_disable (p); +sh_mtu2_disable (ch); disabled =1 ;break ;default :
@@ -202,12 +211,13 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC : -dev_info (&p->pdev->dev,"used for periodic clock events\n" ); -sh_mtu2_enable (p); +dev_info (&ch->mtu->pdev->dev, +"used for periodic clock events\n" ); +sh_mtu2_enable (ch);break ;case CLOCK_EVT_MODE_UNUSED :if (!disabled) -sh_mtu2_disable (p); +sh_mtu2_disable (ch);break ;case CLOCK_EVT_MODE_SHUTDOWN :default :
@@ -217,18 +227,18 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,static void sh_mtu2_clock_event_suspend (struct clock_event_device *ced) { -pm_genpd_syscore_poweroff (&ced_to_sh_mtu2 (ced)->pdev->dev); +pm_genpd_syscore_poweroff (&ced_to_sh_mtu2 (ced)->mtu->pdev->dev); }static void sh_mtu2_clock_event_resume (struct clock_event_device *ced) { -pm_genpd_syscore_poweron (&ced_to_sh_mtu2 (ced)->pdev->dev); +pm_genpd_syscore_poweron (&ced_to_sh_mtu2 (ced)->mtu->pdev->dev); } -static void sh_mtu2_register_clockevent (struct sh_mtu2_priv *p, +static void sh_mtu2_register_clockevent (struct sh_mtu2_channel *ch,char *name,unsigned long rating) { -struct clock_event_device *ced = &p->ced; +struct clock_event_device *ced = &ch->ced;int ret;memset (ced,0 ,sizeof (*ced));
@@ -241,23 +251,24 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, ced->suspend = sh_mtu2_clock_event_suspend; ced->resume = sh_mtu2_clock_event_resume; -dev_info (&p->pdev->dev,"used for clock events\n" ); +dev_info (&ch->mtu->pdev->dev,"used for clock events\n" );clockevents_register_device (ced); - ret =request_irq (p->irq, sh_mtu2_interrupt, + ret =request_irq (ch->irq, sh_mtu2_interrupt,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING , -dev_name (&p->pdev->dev), p); +dev_name (&ch->mtu->pdev->dev), ch);if (ret) { -dev_err (&p->pdev->dev,"failed to request irq %d\n" , p->irq); +dev_err (&ch->mtu->pdev->dev,"failed to request irq %d\n" , + ch->irq);return ; } } -static int sh_mtu2_register (struct sh_mtu2_priv *p,char *name, +static int sh_mtu2_register (struct sh_mtu2_channel *ch,char *name,unsigned long clockevent_rating) {if (clockevent_rating) -sh_mtu2_register_clockevent (p, name, clockevent_rating); +sh_mtu2_register_clockevent (ch, name, clockevent_rating);return 0 ; }
@@ -285,8 +296,8 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) goto err0; } - p->irq =platform_get_irq (p->pdev,0 ); -if (p->irq <0 ) { + p->channel.irq =platform_get_irq (p->pdev,0 ); +if (p->channel.irq <0 ) {dev_err (&p->pdev->dev,"failed to get irq\n" ); goto err0; }
@@ -310,7 +321,9 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)if (ret <0 ) goto err2; - ret =sh_mtu2_register (p, (char *)dev_name (&p->pdev->dev), + p->channel.mtu = p; + + ret =sh_mtu2_register (&p->channel, (char *)dev_name (&p->pdev->dev), cfg->clockevent_rating);if (ret <0 ) goto err3;
Signature · 1 line
1.7.9.5
PATCH 39/71 clocksource: sh_mtu2: Rename struct sh_mtu2_priv to sh_mtu2_device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Channel data is private as well, rename priv to device to make the distrinction between the core device and the channels clearer.
--- drivers/clocksource/sh_mtu2.c | 65 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 32 deletions(-)
drivers/clocksource/sh_mtu2.c +33 -32
@@ -34,15 +34,15 @@#include <linux/pm_domain.h> #include <linux/pm_runtime.h> -struct sh_mtu2_priv ; +struct sh_mtu2_device ;struct sh_mtu2_channel { -struct sh_mtu2_priv *mtu; +struct sh_mtu2_device *mtu;int irq;struct clock_event_device ced; }; -struct sh_mtu2_priv { +struct sh_mtu2_device {struct platform_device *pdev;void __iomem *mapbase;
@@ -273,75 +273,76 @@ static int sh_mtu2_register(struct sh_mtu2_channel *ch, char *name,return 0 ; } -static int sh_mtu2_setup (struct sh_mtu2_priv *p,struct platform_device *pdev) +static int sh_mtu2_setup (struct sh_mtu2_device *mtu, +struct platform_device *pdev) {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res;int ret; ret = -ENXIO ; -memset (p,0 ,sizeof (*p)); - p->pdev = pdev; +memset (mtu,0 ,sizeof (*mtu)); + mtu->pdev = pdev;if (!cfg) { -dev_err (&p->pdev->dev,"missing platform data\n" ); +dev_err (&mtu->pdev->dev,"missing platform data\n" ); goto err0; } -platform_set_drvdata (pdev, p); +platform_set_drvdata (pdev, mtu); - res =platform_get_resource (p->pdev,IORESOURCE_MEM ,0 ); + res =platform_get_resource (mtu->pdev,IORESOURCE_MEM ,0 );if (!res) { -dev_err (&p->pdev->dev,"failed to get I/O memory\n" ); +dev_err (&mtu->pdev->dev,"failed to get I/O memory\n" ); goto err0; } - p->channel.irq =platform_get_irq (p->pdev,0 ); -if (p->channel.irq <0 ) { -dev_err (&p->pdev->dev,"failed to get irq\n" ); + mtu->channel.irq =platform_get_irq (mtu->pdev,0 ); +if (mtu->channel.irq <0 ) { +dev_err (&mtu->pdev->dev,"failed to get irq\n" ); goto err0; }/* map memory, let mapbase point to our channel */ - p->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (p->mapbase ==NULL ) { -dev_err (&p->pdev->dev,"failed to remap I/O memory\n" ); + mtu->mapbase =ioremap_nocache (res->start,resource_size (res)); +if (mtu->mapbase ==NULL ) { +dev_err (&mtu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; }/* get hold of clock */ - p->clk =clk_get (&p->pdev->dev,"mtu2_fck" ); -if (IS_ERR (p->clk)) { -dev_err (&p->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (p->clk); + mtu->clk =clk_get (&mtu->pdev->dev,"mtu2_fck" ); +if (IS_ERR (mtu->clk)) { +dev_err (&mtu->pdev->dev,"cannot get clock\n" ); + ret =PTR_ERR (mtu->clk); goto err1; } - ret =clk_prepare (p->clk); + ret =clk_prepare (mtu->clk);if (ret <0 ) goto err2; - p->channel.mtu = p; + mtu->channel.mtu = mtu; - ret =sh_mtu2_register (&p->channel, (char *)dev_name (&p->pdev->dev), + ret =sh_mtu2_register (&mtu->channel, (char *)dev_name (&mtu->pdev->dev), cfg->clockevent_rating);if (ret <0 ) goto err3;return 0 ; err3: -clk_unprepare (p->clk); +clk_unprepare (mtu->clk); err2: -clk_put (p->clk); +clk_put (mtu->clk); err1: -iounmap (p->mapbase); +iounmap (mtu->mapbase); err0:return ret; }static int sh_mtu2_probe (struct platform_device *pdev) { -struct sh_mtu2_priv *p =platform_get_drvdata (pdev); +struct sh_mtu2_device *mtu =platform_get_drvdata (pdev);struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;
@@ -350,20 +351,20 @@ static int sh_mtu2_probe(struct platform_device *pdev)pm_runtime_enable (&pdev->dev); } -if (p) { +if (mtu) {dev_info (&pdev->dev,"kept as earlytimer\n" ); goto out; } - p =kmalloc (sizeof (*p),GFP_KERNEL ); -if (p ==NULL ) { + mtu =kmalloc (sizeof (*mtu),GFP_KERNEL ); +if (mtu ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ; } - ret =sh_mtu2_setup (p, pdev); + ret =sh_mtu2_setup (mtu, pdev);if (ret) { -kfree (p); +kfree (mtu);pm_runtime_idle (&pdev->dev);return ret; }
Signature · 1 line
1.7.9.5
PATCH 40/71 clocksource: sh_mtu2: Split channel setup to separate function
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Move the channel setup code from sh_mtu2_setup to a new sh_mtu2_setup_channel function and call it from sh_mtu2_setup.
--- drivers/clocksource/sh_mtu2.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/clocksource/sh_mtu2.c +19 -10
@@ -273,6 +273,24 @@ static int sh_mtu2_register(struct sh_mtu2_channel *ch, char *name,return 0 ; } +static int sh_mtu2_setup_channel (struct sh_mtu2_channel *ch, +struct sh_mtu2_device *mtu) +{ +struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; + +memset (ch,0 ,sizeof (*ch)); + ch->mtu = mtu; + + ch->irq =platform_get_irq (mtu->pdev,0 ); +if (ch->irq <0 ) { +dev_err (&mtu->pdev->dev,"failed to get irq\n" ); +return ch->irq; + } + +return sh_mtu2_register (ch, (char *)dev_name (&mtu->pdev->dev), + cfg->clockevent_rating); +} +static int sh_mtu2_setup (struct sh_mtu2_device *mtu,struct platform_device *pdev) {
@@ -297,12 +315,6 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, goto err0; } - mtu->channel.irq =platform_get_irq (mtu->pdev,0 ); -if (mtu->channel.irq <0 ) { -dev_err (&mtu->pdev->dev,"failed to get irq\n" ); - goto err0; - } -/* map memory, let mapbase point to our channel */ mtu->mapbase =ioremap_nocache (res->start,resource_size (res));if (mtu->mapbase ==NULL ) {
@@ -322,10 +334,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,if (ret <0 ) goto err2; - mtu->channel.mtu = mtu; - - ret =sh_mtu2_register (&mtu->channel, (char *)dev_name (&mtu->pdev->dev), - cfg->clockevent_rating); + ret =sh_mtu2_setup_channel (&mtu->channel, mtu);if (ret <0 ) goto err3;
Signature · 1 line
1.7.9.5
PATCH 41/71 clocksource: sh_mtu2: Constify name argument to sh_mtu2_register()
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The name argument is assigned to const structure fields only, constify it.
--- drivers/clocksource/sh_mtu2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/clocksource/sh_mtu2.c +3 -3
@@ -236,7 +236,7 @@ static void sh_mtu2_clock_event_resume(struct clock_event_device *ced) }static void sh_mtu2_register_clockevent (struct sh_mtu2_channel *ch, -char *name,unsigned long rating) +const char *name,unsigned long rating) {struct clock_event_device *ced = &ch->ced;int ret;
@@ -264,7 +264,7 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, } } -static int sh_mtu2_register (struct sh_mtu2_channel *ch,char *name, +static int sh_mtu2_register (struct sh_mtu2_channel *ch,const char *name,unsigned long clockevent_rating) {if (clockevent_rating)
@@ -287,7 +287,7 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch,return ch->irq; } -return sh_mtu2_register (ch, (char *)dev_name (&mtu->pdev->dev), +return sh_mtu2_register (ch,dev_name (&mtu->pdev->dev), cfg->clockevent_rating); }
Signature · 1 line
1.7.9.5
PATCH 42/71 clocksource: sh_mtu2: Add memory base to sh_mtu2_channel structure
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The channel memory base is channel-specific, add it to the channel structure in preparation for support of multiple channels per device.
--- drivers/clocksource/sh_mtu2.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-)
drivers/clocksource/sh_mtu2.c +18 -14
@@ -38,7 +38,10 @@ struct sh_mtu2_device;struct sh_mtu2_channel {struct sh_mtu2_device *mtu; + +void __iomem *base;int irq; +struct clock_event_device ced; };
@@ -74,39 +77,35 @@ static unsigned long mtu2_reg_offs[] = {static inline unsigned long sh_mtu2_read (struct sh_mtu2_channel *ch,int reg_nr) { -struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data; -void __iomem *base = ch->mtu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) -return ioread8 (base + cfg->channel_offset); +return ioread8 (ch->mtu->mapbase); offs = mtu2_reg_offs[reg_nr];if ((reg_nr ==TCNT ) || (reg_nr ==TGR )) -return ioread16 (base + offs); +return ioread16 (ch->base + offs);else -return ioread8 (base + offs); +return ioread8 (ch->base + offs); }static inline void sh_mtu2_write (struct sh_mtu2_channel *ch,int reg_nr,unsigned long value) { -struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data; -void __iomem *base = ch->mtu->mapbase;unsigned long offs;if (reg_nr ==TSTR ) { -iowrite8 (value, base + cfg->channel_offset); +iowrite8 (value, ch->mtu->mapbase);return ; } offs = mtu2_reg_offs[reg_nr];if ((reg_nr ==TCNT ) || (reg_nr ==TGR )) -iowrite16 (value, base + offs); +iowrite16 (value, ch->base + offs);else -iowrite8 (value, base + offs); +iowrite8 (value, ch->base + offs); }static void sh_mtu2_start_stop_ch (struct sh_mtu2_channel *ch,int start)
@@ -315,13 +314,18 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, goto err0; } -/* map memory, let mapbase point to our channel */ - mtu->mapbase =ioremap_nocache (res->start,resource_size (res)); -if (mtu->mapbase ==NULL ) { +/* +* Map memory, let channel.base point to our channel and mapbase to the +* start/stop shared register. +*/ + mtu->channel.base =ioremap_nocache (res->start,resource_size (res)); +if (mtu->channel.base ==NULL ) {dev_err (&mtu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; } + mtu->mapbase = mtu->channel.base + cfg->channel_offset; +/* get hold of clock */ mtu->clk =clk_get (&mtu->pdev->dev,"mtu2_fck" );if (IS_ERR (mtu->clk)) {
@@ -344,7 +348,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, err2:clk_put (mtu->clk); err1: -iounmap (mtu->mapbase); +iounmap (mtu->channel.base); err0:return ret; }
Signature · 1 line
1.7.9.5
PATCH 43/71 clocksource: sh_mtu2: Add index to struct sh_mtu2_channel
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Use the index as the timer start/stop bit and when printing messages to identify the channel.
--- drivers/clocksource/sh_mtu2.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
drivers/clocksource/sh_mtu2.c +13 -9
@@ -38,6 +38,7 @@ struct sh_mtu2_device;struct sh_mtu2_channel {struct sh_mtu2_device *mtu; +unsigned int index;void __iomem *base;int irq;
@@ -110,7 +111,6 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr,static void sh_mtu2_start_stop_ch (struct sh_mtu2_channel *ch,int start) { -struct sh_timer_config *cfg = ch->mtu->pdev->dev.platform_data;unsigned long flags, value;/* start stop register shared by multiple timer channels */
@@ -118,9 +118,9 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) value =sh_mtu2_read (ch,TSTR );if (start) - value |=1 << cfg->timer_bit; + value |=1 << ch->index;else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << ch->index);sh_mtu2_write (ch,TSTR , value);raw_spin_unlock_irqrestore (&sh_mtu2_lock, flags);
@@ -138,7 +138,8 @@ static int sh_mtu2_enable(struct sh_mtu2_channel *ch)/* enable clock */ ret =clk_enable (ch->mtu->clk);if (ret) { -dev_err (&ch->mtu->pdev->dev,"cannot enable clock\n" ); +dev_err (&ch->mtu->pdev->dev,"ch%u: cannot enable clock\n" , + ch->index);return ret; }
@@ -211,7 +212,7 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,switch (mode) {case CLOCK_EVT_MODE_PERIODIC :dev_info (&ch->mtu->pdev->dev, -"used for periodic clock events\n" ); +"ch%u: used for periodic clock events\n" , ch->index);sh_mtu2_enable (ch);break ;case CLOCK_EVT_MODE_UNUSED :
@@ -250,15 +251,16 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, ced->suspend = sh_mtu2_clock_event_suspend; ced->resume = sh_mtu2_clock_event_resume; -dev_info (&ch->mtu->pdev->dev,"used for clock events\n" ); +dev_info (&ch->mtu->pdev->dev,"ch%u: used for clock events\n" , + ch->index);clockevents_register_device (ced); ret =request_irq (ch->irq, sh_mtu2_interrupt,IRQF_TIMER |IRQF_IRQPOLL |IRQF_NOBALANCING ,dev_name (&ch->mtu->pdev->dev), ch);if (ret) { -dev_err (&ch->mtu->pdev->dev,"failed to request irq %d\n" , - ch->irq); +dev_err (&ch->mtu->pdev->dev,"ch%u: failed to request irq %d\n" , + ch->index, ch->irq);return ; } }
@@ -279,10 +281,12 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch,memset (ch,0 ,sizeof (*ch)); ch->mtu = mtu; + ch->index = cfg->timer_bit; ch->irq =platform_get_irq (mtu->pdev,0 );if (ch->irq <0 ) { -dev_err (&mtu->pdev->dev,"failed to get irq\n" ); +dev_err (&mtu->pdev->dev,"ch%u: failed to get irq\n" , + ch->index);return ch->irq; }
Signature · 1 line
1.7.9.5
PATCH 44/71 clocksource: sh_mtu2: Replace kmalloc + memset with kzalloc
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
One kzalloc a day keeps the bugs away.
--- drivers/clocksource/sh_mtu2.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/clocksource/sh_mtu2.c +1 -5
@@ -241,8 +241,6 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,struct clock_event_device *ced = &ch->ced;int ret; -memset (ced,0 ,sizeof (*ced)); - ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->rating = rating;
@@ -279,7 +277,6 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, {struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; -memset (ch,0 ,sizeof (*ch)); ch->mtu = mtu; ch->index = cfg->timer_bit;
@@ -302,7 +299,6 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,int ret; ret = -ENXIO ; -memset (mtu,0 ,sizeof (*mtu)); mtu->pdev = pdev;if (!cfg) {
@@ -373,7 +369,7 @@ static int sh_mtu2_probe(struct platform_device *pdev) goto out; } - mtu =kmalloc (sizeof (*mtu),GFP_KERNEL ); + mtu =kzalloc (sizeof (*mtu),GFP_KERNEL );if (mtu ==NULL ) {dev_err (&pdev->dev,"failed to allocate driver data\n" );return -ENOMEM ;
Signature · 1 line
1.7.9.5
PATCH 45/71 clocksource: sh_mtu2: Allocate channels dynamically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This prepares the driver for multi-channel support.
--- drivers/clocksource/sh_mtu2.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
drivers/clocksource/sh_mtu2.c +20 -7
@@ -52,7 +52,8 @@ struct sh_mtu2_device {void __iomem *mapbase;struct clk *clk; -struct sh_mtu2_channel channel; +struct sh_mtu2_channel *channels; +unsigned int num_channels; };static DEFINE_RAW_SPINLOCK (sh_mtu2_lock);
@@ -296,6 +297,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, {struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; +void __iomem *base;int ret; ret = -ENXIO ;
@@ -315,16 +317,16 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, }/* -* Map memory, let channel.base point to our channel and mapbase to the +* Map memory, let base point to our channel and mapbase to the * start/stop shared register. */ - mtu->channel.base =ioremap_nocache (res->start,resource_size (res)); -if (mtu->channel.base ==NULL ) { + base =ioremap_nocache (res->start,resource_size (res)); +if (base ==NULL ) {dev_err (&mtu->pdev->dev,"failed to remap I/O memory\n" ); goto err0; } - mtu->mapbase = mtu->channel.base + cfg->channel_offset; + mtu->mapbase = base + cfg->channel_offset;/* get hold of clock */ mtu->clk =clk_get (&mtu->pdev->dev,"mtu2_fck" );
@@ -338,17 +340,28 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,if (ret <0 ) goto err2; - ret =sh_mtu2_setup_channel (&mtu->channel, mtu); + mtu->channels =kzalloc (sizeof (*mtu->channels),GFP_KERNEL ); +if (mtu->channels ==NULL ) { + ret = -ENOMEM ; + goto err3; + } + + mtu->num_channels =1 ; + + mtu->channels[0 ].base = base; + + ret =sh_mtu2_setup_channel (&mtu->channels[0 ], mtu);if (ret <0 ) goto err3;return 0 ; err3: +kfree (mtu->channels);clk_unprepare (mtu->clk); err2:clk_put (mtu->clk); err1: -iounmap (mtu->channel.base); +iounmap (base); err0:return ret; }
Signature · 1 line
1.7.9.5
PATCH 46/71 clocksource: sh_mtu2: Replace hardcoded register values with macros
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Define symbolic macros for all used registers bits.
--- drivers/clocksource/sh_mtu2.c | 98 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 6 deletions(-)
drivers/clocksource/sh_mtu2.c +92 -6
@@ -67,6 +67,88 @@ static DEFINE_RAW_SPINLOCK(sh_mtu2_lock);#define TCNT 5/* channel register */ #define TGR 6/* channel register */ +#define TCR_CCLR_NONE (0 << 5) +#define TCR_CCLR_TGRA (1 << 5) +#define TCR_CCLR_TGRB (2 << 5) +#define TCR_CCLR_SYNC (3 << 5) +#define TCR_CCLR_TGRC (5 << 5) +#define TCR_CCLR_TGRD (6 << 5) +#define TCR_CCLR_MASK (7 << 5) +#define TCR_CKEG_RISING (0 << 3) +#define TCR_CKEG_FALLING (1 << 3) +#define TCR_CKEG_BOTH (2 << 3) +#define TCR_CKEG_MASK (3 << 3) +/* Values 4 to 7 are channel-dependent */ +#define TCR_TPSC_P1 (0 << 0) +#define TCR_TPSC_P4 (1 << 0) +#define TCR_TPSC_P16 (2 << 0) +#define TCR_TPSC_P64 (3 << 0) +#define TCR_TPSC_CH0_TCLKA (4 << 0) +#define TCR_TPSC_CH0_TCLKB (5 << 0) +#define TCR_TPSC_CH0_TCLKC (6 << 0) +#define TCR_TPSC_CH0_TCLKD (7 << 0) +#define TCR_TPSC_CH1_TCLKA (4 << 0) +#define TCR_TPSC_CH1_TCLKB (5 << 0) +#define TCR_TPSC_CH1_P256 (6 << 0) +#define TCR_TPSC_CH1_TCNT2 (7 << 0) +#define TCR_TPSC_CH2_TCLKA (4 << 0) +#define TCR_TPSC_CH2_TCLKB (5 << 0) +#define TCR_TPSC_CH2_TCLKC (6 << 0) +#define TCR_TPSC_CH2_P1024 (7 << 0) +#define TCR_TPSC_CH34_P256 (4 << 0) +#define TCR_TPSC_CH34_P1024 (5 << 0) +#define TCR_TPSC_CH34_TCLKA (6 << 0) +#define TCR_TPSC_CH34_TCLKB (7 << 0) +#define TCR_TPSC_MASK (7 << 0) + +#define TMDR_BFE (1 << 6) +#define TMDR_BFB (1 << 5) +#define TMDR_BFA (1 << 4) +#define TMDR_MD_NORMAL (0 << 0) +#define TMDR_MD_PWM_1 (2 << 0) +#define TMDR_MD_PWM_2 (3 << 0) +#define TMDR_MD_PHASE_1 (4 << 0) +#define TMDR_MD_PHASE_2 (5 << 0) +#define TMDR_MD_PHASE_3 (6 << 0) +#define TMDR_MD_PHASE_4 (7 << 0) +#define TMDR_MD_PWM_SYNC (8 << 0) +#define TMDR_MD_PWM_COMP_CREST (13 << 0) +#define TMDR_MD_PWM_COMP_TROUGH (14 << 0) +#define TMDR_MD_PWM_COMP_BOTH (15 << 0) +#define TMDR_MD_MASK (15 << 0) + +#define TIOC_IOCH (n) ((n) << 4) +#define TIOC_IOCL (n) ((n) << 0) +#define TIOR_OC_RETAIN (0 << 0) +#define TIOR_OC_0_CLEAR (1 << 0) +#define TIOR_OC_0_SET (2 << 0) +#define TIOR_OC_0_TOGGLE (3 << 0) +#define TIOR_OC_1_CLEAR (5 << 0) +#define TIOR_OC_1_SET (6 << 0) +#define TIOR_OC_1_TOGGLE (7 << 0) +#define TIOR_IC_RISING (8 << 0) +#define TIOR_IC_FALLING (9 << 0) +#define TIOR_IC_BOTH (10 << 0) +#define TIOR_IC_TCNT (12 << 0) +#define TIOR_MASK (15 << 0) + +#define TIER_TTGE (1 << 7) +#define TIER_TTGE2 (1 << 6) +#define TIER_TCIEU (1 << 5) +#define TIER_TCIEV (1 << 4) +#define TIER_TGIED (1 << 3) +#define TIER_TGIEC (1 << 2) +#define TIER_TGIEB (1 << 1) +#define TIER_TGIEA (1 << 0) + +#define TSR_TCFD (1 << 7) +#define TSR_TCFU (1 << 5) +#define TSR_TCFV (1 << 4) +#define TSR_TGFD (1 << 3) +#define TSR_TGFC (1 << 2) +#define TSR_TGFB (1 << 1) +#define TSR_TGFA (1 << 0) +static unsigned long mtu2_reg_offs[] = { [TCR ] =0 , [TMDR ] =1 ,
@@ -150,13 +232,17 @@ static int sh_mtu2_enable(struct sh_mtu2_channel *ch) rate =clk_get_rate (ch->mtu->clk) /64 ; periodic = (rate +HZ /2 ) /HZ ; -/* "Periodic Counter Operation" */ -sh_mtu2_write (ch,TCR ,0x23 );/* TGRA clear, divide clock by 64 */ -sh_mtu2_write (ch,TIOR ,0 ); +/* +* "Periodic Counter Operation" +* Clear on TGRA compare match, divide clock by 64. +*/ +sh_mtu2_write (ch,TCR ,TCR_CCLR_TGRA |TCR_TPSC_P64 ); +sh_mtu2_write (ch,TIOR ,TIOC_IOCH (TIOR_OC_0_CLEAR ) | +TIOC_IOCL (TIOR_OC_0_CLEAR ));sh_mtu2_write (ch,TGR , periodic);sh_mtu2_write (ch,TCNT ,0 ); -sh_mtu2_write (ch,TMDR ,0 ); -sh_mtu2_write (ch,TIER ,0x01 ); +sh_mtu2_write (ch,TMDR ,TMDR_MD_NORMAL ); +sh_mtu2_write (ch,TIER ,TIER_TGIEA );/* enable channel */ sh_mtu2_start_stop_ch (ch,1 );
@@ -182,7 +268,7 @@ static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)/* acknowledge interrupt */ sh_mtu2_read (ch,TSR ); -sh_mtu2_write (ch,TSR ,0xfe ); +sh_mtu2_write (ch,TSR , ~TSR_TGFA );/* notify clockevent layer */ ch->ced.event_handler (&ch->ced);
Signature · 1 line
1.7.9.5
PATCH 47/71 clocksource: sh_mtu2: Set cpumask to cpu_possible_mask
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The MTU2 is not tied to CPU0, make it usable on any CPU.
--- drivers/clocksource/sh_mtu2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/sh_mtu2.c +1 -1
@@ -331,7 +331,7 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; ced->rating = rating; - ced->cpumask =cpumask_of (0 ); + ced->cpumask = cpu_possible_mask; ced->set_mode = sh_mtu2_clock_event_mode; ced->suspend = sh_mtu2_clock_event_suspend; ced->resume = sh_mtu2_clock_event_resume;
Signature · 1 line
1.7.9.5
PATCH 48/71 clocksource: sh_mtu2: Hardcode MTU2 clock event rating to 200
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
All boards use clock event ratings of 200 for the MTU2, hardcode it in the driver.
--- drivers/clocksource/sh_mtu2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/clocksource/sh_mtu2.c +6 -6
@@ -323,14 +323,14 @@ static void sh_mtu2_clock_event_resume(struct clock_event_device *ced) }static void sh_mtu2_register_clockevent (struct sh_mtu2_channel *ch, -const char *name,unsigned long rating) +const char *name) {struct clock_event_device *ced = &ch->ced;int ret; ced->name = name; ced->features =CLOCK_EVT_FEAT_PERIODIC ; - ced->rating = rating; + ced->rating =200 ; ced->cpumask = cpu_possible_mask; ced->set_mode = sh_mtu2_clock_event_mode; ced->suspend = sh_mtu2_clock_event_suspend;
@@ -351,10 +351,10 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, }static int sh_mtu2_register (struct sh_mtu2_channel *ch,const char *name, -unsigned long clockevent_rating) +bool clockevent) { -if (clockevent_rating) -sh_mtu2_register_clockevent (ch, name, clockevent_rating); +if (clockevent) +sh_mtu2_register_clockevent (ch, name);return 0 ; }
@@ -375,7 +375,7 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, }return sh_mtu2_register (ch,dev_name (&mtu->pdev->dev), - cfg->clockevent_rating); + cfg->clockevent_rating !=0 ); } static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
Signature · 1 line
1.7.9.5
PATCH 49/71 clocksource: sh_mtu2: Add support for multiple channels per device
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
MTU2 hardware devices can support multiple channels, with global registers and per-channel registers. The sh_mtu2 driver currently models the hardware with one Linux device per channel. This model makes it difficult to handle global registers in a clean way.
Add support for a new model that uses one Linux device per timer with multiple channels per device. This requires changes to platform data, add new channel configuration fields.
Support for the legacy model is kept and will be removed after all platforms switch to the new model.
--- drivers/clocksource/sh_mtu2.c | 184 +++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 54 deletions(-)
drivers/clocksource/sh_mtu2.c +130 -54
@@ -54,6 +54,9 @@ struct sh_mtu2_device {struct sh_mtu2_channel *channels;unsigned int num_channels; + +bool legacy; +bool has_clockevent; };static DEFINE_RAW_SPINLOCK (sh_mtu2_lock);
@@ -163,8 +166,12 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr) {unsigned long offs; -if (reg_nr ==TSTR ) -return ioread8 (ch->mtu->mapbase); +if (reg_nr ==TSTR ) { +if (ch->mtu->legacy) +return ioread8 (ch->mtu->mapbase); +else +return ioread8 (ch->mtu->mapbase +0x280 ); + } offs = mtu2_reg_offs[reg_nr];
@@ -180,8 +187,10 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr,unsigned long offs;if (reg_nr ==TSTR ) { -iowrite8 (value, ch->mtu->mapbase); -return ; +if (ch->mtu->legacy) +return iowrite8 (value, ch->mtu->mapbase); +else +return iowrite8 (value, ch->mtu->mapbase +0x280 ); } offs = mtu2_reg_offs[reg_nr];
@@ -353,109 +362,168 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,static int sh_mtu2_register (struct sh_mtu2_channel *ch,const char *name,bool clockevent) { -if (clockevent) +if (clockevent) { + ch->mtu->has_clockevent = true;sh_mtu2_register_clockevent (ch, name); + }return 0 ; } -static int sh_mtu2_setup_channel (struct sh_mtu2_channel *ch, +static int sh_mtu2_setup_channel (struct sh_mtu2_channel *ch,unsigned int index,struct sh_mtu2_device *mtu) { -struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; +static const unsigned int channel_offsets[] = { +0x300 ,0x380 ,0x000 , + }; +bool clockevent; ch->mtu = mtu; - ch->index = cfg->timer_bit; - ch->irq =platform_get_irq (mtu->pdev,0 ); +if (mtu->legacy) { +struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; + + clockevent = cfg->clockevent_rating !=0 ; + + ch->irq =platform_get_irq (mtu->pdev,0 ); + ch->base = mtu->mapbase - cfg->channel_offset; + ch->index = cfg->timer_bit; + }else { +char name[6 ]; + + clockevent = true; + +sprintf (name,"tgi%ua" , index); + ch->irq =platform_get_irq_byname (mtu->pdev, name); + ch->base = mtu->mapbase + channel_offsets[index]; + ch->index = index; + } +if (ch->irq <0 ) { +/* Skip channels with no declared interrupt. */ +if (!mtu->legacy) +return 0 ; +dev_err (&mtu->pdev->dev,"ch%u: failed to get irq\n" , ch->index);return ch->irq; } -return sh_mtu2_register (ch,dev_name (&mtu->pdev->dev), - cfg->clockevent_rating !=0 ); +return sh_mtu2_register (ch,dev_name (&mtu->pdev->dev), clockevent); } -static int sh_mtu2_setup (struct sh_mtu2_device *mtu, -struct platform_device *pdev) +static int sh_mtu2_map_memory (struct sh_mtu2_device *mtu) { -struct sh_timer_config *cfg = pdev->dev.platform_data;struct resource *res; -void __iomem *base; -int ret; - ret = -ENXIO ; - - mtu->pdev = pdev; - -if (!cfg) { -dev_err (&mtu->pdev->dev,"missing platform data\n" ); - goto err0; - } - -platform_set_drvdata (pdev, mtu); res =platform_get_resource (mtu->pdev,IORESOURCE_MEM ,0 );if (!res) {dev_err (&mtu->pdev->dev,"failed to get I/O memory\n" ); - goto err0; +return -ENXIO ; } + mtu->mapbase =ioremap_nocache (res->start,resource_size (res)); +if (mtu->mapbase ==NULL ) +return -ENXIO ; +/* -* Map memory, let base point to our channel and mapbase to the -* start/stop shared register. +* In legacy platform device configuration (with one device per channel) +* the resource points to the channel base address. */ - base =ioremap_nocache (res->start,resource_size (res)); -if (base ==NULL ) { -dev_err (&mtu->pdev->dev,"failed to remap I/O memory\n" ); - goto err0; +if (mtu->legacy) { +struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; + mtu->mapbase += cfg->channel_offset; + } + +return 0 ; +} + +static void sh_mtu2_unmap_memory (struct sh_mtu2_device *mtu) +{ +if (mtu->legacy) { +struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; + mtu->mapbase -= cfg->channel_offset; } - mtu->mapbase = base + cfg->channel_offset; +iounmap (mtu->mapbase); +} + +static int sh_mtu2_setup (struct sh_mtu2_device *mtu, +struct platform_device *pdev) +{ +struct sh_timer_config *cfg = pdev->dev.platform_data; +const struct platform_device_id *id = pdev->id_entry; +unsigned int i; +int ret; + + mtu->pdev = pdev; + mtu->legacy = id->driver_data; + +if (mtu->legacy && !cfg) { +dev_err (&mtu->pdev->dev,"missing platform data\n" ); +return -ENXIO ; + } -/* get hold of clock */ +/* Get hold of clock. */ mtu->clk =clk_get (&mtu->pdev->dev,"mtu2_fck" );if (IS_ERR (mtu->clk)) {dev_err (&mtu->pdev->dev,"cannot get clock\n" ); - ret =PTR_ERR (mtu->clk); - goto err1; +return PTR_ERR (mtu->clk); } ret =clk_prepare (mtu->clk);if (ret <0 ) - goto err2; + goto err_clk_put; - mtu->channels =kzalloc (sizeof (*mtu->channels),GFP_KERNEL ); +/* Map the memory resource. */ + ret =sh_mtu2_map_memory (mtu); +if (ret <0 ) { +dev_err (&mtu->pdev->dev,"failed to remap I/O memory\n" ); + goto err_clk_unprepare; + } + +/* Allocate and setup the channels. */ +if (mtu->legacy) + mtu->num_channels =1 ; +else + mtu->num_channels =3 ; + + mtu->channels =kzalloc (sizeof (*mtu->channels) * mtu->num_channels, +GFP_KERNEL );if (mtu->channels ==NULL ) { ret = -ENOMEM ; - goto err3; + goto err_unmap; } - mtu->num_channels =1 ; - - mtu->channels[0 ].base = base; +if (mtu->legacy) { + ret =sh_mtu2_setup_channel (&mtu->channels[0 ],0 , mtu); +if (ret <0 ) + goto err_unmap; + }else { +for (i =0 ; i < mtu->num_channels; ++i) { + ret =sh_mtu2_setup_channel (&mtu->channels[i], i, mtu); +if (ret <0 ) + goto err_unmap; + } + } - ret =sh_mtu2_setup_channel (&mtu->channels[0 ], mtu); -if (ret <0 ) - goto err3; +platform_set_drvdata (pdev, mtu);return 0 ; - err3: + +err_unmap:kfree (mtu->channels); +sh_mtu2_unmap_memory (mtu); +err_clk_unprepare:clk_unprepare (mtu->clk); - err2: +err_clk_put:clk_put (mtu->clk); - err1: -iounmap (base); - err0:return ret; }static int sh_mtu2_probe (struct platform_device *pdev) {struct sh_mtu2_device *mtu =platform_get_drvdata (pdev); -struct sh_timer_config *cfg = pdev->dev.platform_data;int ret;if (!is_early_platform_device (pdev)) {
@@ -484,7 +552,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)return 0 ; out: -if (cfg->clockevent_rating) +if (mtu->has_clockevent)pm_runtime_irq_safe (&pdev->dev);else pm_runtime_idle (&pdev->dev);
@@ -497,12 +565,20 @@ static int sh_mtu2_remove(struct platform_device *pdev)return -EBUSY ;/* cannot unregister clockevent */ } +static const struct platform_device_id sh_mtu2_id_table[] = { + {"sh_mtu2" ,1 }, + {"sh-mtu2" ,0 }, + { }, +}; +MODULE_DEVICE_TABLE (platform, sh_mtu2_id_table); +static struct platform_driver sh_mtu2_device_driver = { .probe = sh_mtu2_probe, .remove = sh_mtu2_remove, .driver = { .name ="sh_mtu2" , - } + }, + .id_table = sh_mtu2_id_table, };static int __init sh_mtu2_init (void )
Signature · 1 line
1.7.9.5
PATCH 50/71 clocksource: sh_mtu2: Rename clock to "fck" in the non-legacy case
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
The sh_mtu2 driver gets the MTU2 functional clock using a connection ID of "mtu2_fck". While all SH SoCs create clock lookup entries with a NULL device ID and a "mtu2_fck" connection ID, the ARM SoCs use the device ID only with a NULL connection ID. This works on legacy platforms but will break on ARM with DT boot.
Fix the situation by using a connection ID of "fck" in the non-legacy platform data case. Clock lookup entries will be renamed to use the device ID as well as the connection ID as platforms get moved to new platform data. The legacy code will eventually be dropped, leaving us with device ID based clock lookup, compatible with DT boot.
--- drivers/clocksource/sh_mtu2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/sh_mtu2.c +1 -1
@@ -465,7 +465,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, }/* Get hold of clock. */ - mtu->clk =clk_get (&mtu->pdev->dev,"mtu2_fck" ); + mtu->clk =clk_get (&mtu->pdev->dev, mtu->legacy ?"mtu2_fck" :"fck" );if (IS_ERR (mtu->clk)) {dev_err (&mtu->pdev->dev,"cannot get clock\n" );return PTR_ERR (mtu->clk);
Signature · 1 line
1.7.9.5
PATCH 51/71 clocksource: sh_mtu2: Remove FSF mail address from GPL notice
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
--- drivers/clocksource/sh_mtu2.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/clocksource/sh_mtu2.c +0 -4
@@ -11,10 +11,6 @@* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h>
Signature · 1 line
1.7.9.5
PATCH 52/71 clocksource: sh_mtu2: Sort headers alphabetically
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
This helps locating duplicates and inserting new headers.
--- drivers/clocksource/sh_mtu2.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/clocksource/sh_mtu2.c +9 -9
@@ -13,22 +13,22 @@* GNU General Public License for more details. */ +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/delay.h> #include <linux/io.h> -#include <linux/clk.h> +#include <linux/ioport.h> #include <linux/irq.h> -#include <linux/err.h> -#include <linux/clockchips.h> -#include <linux/sh_timer.h> -#include <linux/slab.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/sh_timer.h> +#include <linux/slab.h> +#include <linux/spinlock.h> struct sh_mtu2_device ;
Signature · 1 line
1.7.9.5
PATCH 53/71 clocksource: arm_global_timer: Only check for unusable timer on A9
In reply to Daniel LezcanoFrom: Matthew Leach <[email protected]>
The check for a usable global timer in the probe code does not enquire which CPU we are currently running on. This can cause the driver to incorrectly assume we have an unusable global timer if we are running on a CPU other than A9.
Before checking the CPU revision, ensure we are running on an A9 CPU.
--- drivers/clocksource/arm_global_timer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clocksource/arm_global_timer.c +3 -2
@@ -246,11 +246,12 @@ static void __init global_timer_of_register(struct device_node *np)int err =0 ;/* -* In r2p0 the comparators for each processor with the global timer +* In A9 r2p0 the comparators for each processor with the global timer * fire when the timer value is greater than or equal to. In previous * revisions the comparators fired when the timer value was equal to. */ -if ((read_cpuid_id () &0xf0000f ) <0x200000 ) { +if (read_cpuid_part_number () ==ARM_CPU_PART_CORTEX_A9 + && (read_cpuid_id () &0xf0000f ) <0x200000 ) {pr_warn ("global-timer: non support for this cpu version.\n" );return ; }
Signature · 1 line
1.7.9.5
PATCH 54/71 documentaion: DT: allow a A5 compatible string in global timer
In reply to Daniel LezcanoFrom: Matthew Leach <[email protected]>
The global timer is present on the Cortex A5. Add a compatibility string to the DT binding to allow a Cortex A5 global timer.
--- .../devicetree/bindings/arm/global_timer.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/arm/global_timer.txt +5 -2
@@ -4,8 +4,11 @@ ** Timer node required properties: -- compatible : Should be "arm,cortex-a9-global-timer" - Driver supports versions r2p0 and above. +- compatible : should contain + * "arm,cortex-a5-global-timer" for Cortex-A5 global timers. + * "arm,cortex-a9-global-timer" for Cortex-A9 global + timers or any compatible implementation. Note: driver + supports versions r2p0 and above. - interrupts : One interrupt to each core
Signature · 1 line
1.7.9.5
PATCH 55/71 dts: ca5: add the global timer for the A5
In reply to Daniel LezcanoFrom: Matthew Leach <[email protected]>
The Cortex A5 contains a global timer: add the appropriate device tree node.
--- arch/arm/boot/dts/vexpress-v2p-ca5s.dts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
arch/arm/boot/dts/vexpress-v2p-ca5s.dts +9 -1
@@ -88,6 +88,14 @@ interrupts = <1 13 0x304>; }; + timer at 2c000200 { + compatible = "arm,cortex-a5-global-timer", + "arm,cortex-a9-global-timer"; + reg = <0x2c000200 0x20>; + interrupts = <1 11 0x304>; + clocks = <&oscclk0>; + }; + watchdog at 2c000620 { compatible = "arm,cortex-a5-twd-wdt"; reg = <0x2c000620 0x20>;
@@ -120,7 +128,7 @@ compatible = "arm,vexpress,config-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; - osc at 0 { + oscclk0: osc at 0 { /* CPU and internal AXI reference clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 0>;
Signature · 1 line
1.7.9.5
PATCH 56/71 KConfig: Vexpress: build the ARM_GLOBAL_TIMER with vexpress platform
In reply to Daniel LezcanoFrom: Matthew Leach <[email protected]>
The Cortex A5 now contains bindings for the global timer driver. Ensure that the driver is built with a vexpress platform.
--- arch/arm/mach-vexpress/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-vexpress/Kconfig +1 -0
@@ -4,6 +4,7 @@ config ARCH_VEXPRESS select ARCH_SUPPORTS_BIG_ENDIAN select ARM_AMBA select ARM_GIC + select ARM_GLOBAL_TIMER select ARM_TIMER_SP804 select COMMON_CLK_VERSATILE select HAVE_ARM_SCU if SMP
Signature · 1 line
1.7.9.5
PATCH 57/71 clocksource: efm32: use $vendor,$device scheme for compatible string
In reply to Daniel LezcanoFrom: Uwe Kleine-K?nig <[email protected]>
Wolfram Sang pointed out that "efm32,$device" is non-standard. So use the common scheme and prefix device with "efm32-". The old compatible string is left in place until arch/arm/boot/dts/efm32* is fixed.
--- .../devicetree/bindings/timer/efm32,timer.txt | 23 -------------------- .../bindings/timer/energymicro,efm32-timer.txt | 23 ++++++++++++++++++++ drivers/clocksource/time-efm32.c | 3 ++- 3 files changed, 25 insertions(+), 24 deletions(-) delete mode 100644 Documentation/devicetree/bindings/timer/efm32,timer.txt create mode 100644 Documentation/devicetree/bindings/timer/energymicro,efm32-timer.txt
Documentation/devicetree/bindings/timer/efm32,timer.txt deleted +0 -23
@@ -1,23 +0,0 @@ -* EFM32 timer hardware - -The efm32 Giant Gecko SoCs come with four 16 bit timers. Two counters can be -connected to form a 32 bit counter. Each timer has three Compare/Capture -channels and can be used as PWM or Quadrature Decoder. Available clock sources -are the cpu's HFPERCLK (with a 10-bit prescaler) or an external pin. - -Required properties: -- compatible : Should be efm32,timer -- reg : Address and length of the register set -- clocks : Should contain a reference to the HFPERCLK - -Optional properties: -- interrupts : Reference to the timer interrupt - -Example: - -timer at 40010c00 { - compatible = "efm32,timer"; - reg = <0x40010c00 0x400>; - interrupts = <14>; - clocks = <&cmu clk_HFPERCLKTIMER3>; -};
Documentation/devicetree/bindings/timer/energymicro,efm32-timer.txt new file +23 -0
@@ -0,0 +1,23 @@ +* EFM32 timer hardware + +The efm32 Giant Gecko SoCs come with four 16 bit timers. Two counters can be +connected to form a 32 bit counter. Each timer has three Compare/Capture +channels and can be used as PWM or Quadrature Decoder. Available clock sources +are the cpu's HFPERCLK (with a 10-bit prescaler) or an external pin. + +Required properties: +- compatible : Should be "energymicro,efm32-timer" +- reg : Address and length of the register set +- clocks : Should contain a reference to the HFPERCLK + +Optional properties: +- interrupts : Reference to the timer interrupt + +Example: + +timer at 40010c00 { + compatible = "energymicro,efm32-timer"; + reg = <0x40010c00 0x400>; + interrupts = <14>; + clocks = <&cmu clk_HFPERCLKTIMER3>; +};
drivers/clocksource/time-efm32.c +2 -1
@@ -272,4 +272,5 @@ static void __init efm32_timer_init(struct device_node *np) } } } -CLOCKSOURCE_OF_DECLARE (efm32,"efm32,timer" , efm32_timer_init); +CLOCKSOURCE_OF_DECLARE (efm32compat,"efm32,timer" , efm32_timer_init); +CLOCKSOURCE_OF_DECLARE (efm32,"energymicro,efm32-timer" , efm32_timer_init);
Signature · 1 line
1.7.9.5
PATCH 58/71 clocksource: sun5i: Add support for reset controller
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
The Allwinner A31 that uses this timer has the timer IP asserted in reset. Add an optional reset property to the DT, and deassert the timer from reset if it's there.
--- .../bindings/timer/allwinner,sun5i-a13-hstimer.txt | 4 ++++ drivers/clocksource/timer-sun5i.c | 6 ++++++ 2 files changed, 10 insertions(+)
Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +4 -0
@@ -9,6 +9,9 @@ Required properties: one) - clocks: phandle to the source clock (usually the AHB clock) +Optionnal properties: +- resets: phandle to a reset controller asserting the timer + Example: timer at 01c60000 {
@@ -19,4 +22,5 @@ timer at 01c60000 { <0 53 1>, <0 54 1>; clocks = <&ahb1_gates 19>; + resets = <&ahb1rst 19>; };
drivers/clocksource/timer-sun5i.c +6 -0
@@ -16,6 +16,7 @@#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqreturn.h> +#include <linux/reset.h> #include <linux/sched_clock.h> #include <linux/of.h> #include <linux/of_address.h>
@@ -143,6 +144,7 @@ static u64 sun5i_timer_sched_read(void)static void __init sun5i_timer_init (struct device_node *node) { +struct reset_control *rstc;unsigned long rate;struct clk *clk;int ret, irq;
@@ -162,6 +164,10 @@ static void __init sun5i_timer_init(struct device_node *node)clk_prepare_enable (clk); rate =clk_get_rate (clk); + rstc =of_reset_control_get (node,NULL ); +if (!IS_ERR (rstc)) +reset_control_deassert (rstc); +writel (~0 , timer_base +TIMER_INTVAL_LO_REG (1 ));writel (TIMER_CTL_ENABLE |TIMER_CTL_RELOAD , timer_base +TIMER_CTL_REG (1 ));
Signature · 1 line
1.7.9.5
PATCH 59/71 ARM: sun6i: a31: Add support for the High Speed Timers
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
The Allwinner A31 has support for four high speed timers. Apart for the number of timers (4 vs 2), it's basically the same logic than the high speed timers found in the sun5i chips.
Now that we have a driver to support it, we can enable them in the device tree.
--- arch/arm/boot/dts/sun6i-a31.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+)
arch/arm/boot/dts/sun6i-a31.dtsi +11 -0
@@ -428,6 +428,17 @@ status = "disabled"; }; + timer at 01c60000 { + compatible = "allwinner,sun6i-a31-hstimer", "allwinner,sun7i-a20-hstimer"; + reg = <0x01c60000 0x1000>; + interrupts = <0 51 4>, + <0 52 4>, + <0 53 4>, + <0 54 4>; + clocks = <&ahb1_gates 19>; + resets = <&ahb1_rst 19>; + }; + spi0: spi at 01c68000 { compatible = "allwinner,sun6i-a31-spi"; reg = <0x01c68000 0x1000>;
Signature · 1 line
1.7.9.5
PATCH 60/71 clocksource: qcom: Implement read_current_timer for udelay
In reply to Daniel LezcanoFrom: Stephen Boyd <[email protected]>
Setup the same timer used as the clocksource to be used as the read_current_timer implementation. This allows us to support a stable udelay implementation on MSMs where it's possible for the CPUs to scale speeds independently of one another.
--- drivers/clocksource/qcom-timer.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/clocksource/qcom-timer.c +13 -0
@@ -26,6 +26,8 @@#include <linux/of_irq.h> #include <linux/sched_clock.h> +#include <asm/delay.h> +#define TIMER_MATCH_VAL 0x0000#define TIMER_COUNT_VAL 0x0004#define TIMER_ENABLE 0x0008
@@ -179,6 +181,15 @@ static u64 notrace msm_sched_clock_read(void)return msm_clocksource.read (&msm_clocksource); } +static unsigned long msm_read_current_timer (void ) +{ +return msm_clocksource.read (&msm_clocksource); +} + +static struct delay_timer msm_delay_timer = { + .read_current_timer = msm_read_current_timer, +}; +static void __init msm_timer_init (u32 dgt_hz,int sched_bits,int irq,bool percpu) {
@@ -217,6 +228,8 @@ err:if (res)pr_err ("clocksource_register failed\n" );sched_clock_register (msm_sched_clock_read, sched_bits, dgt_hz); + msm_delay_timer.freq = dgt_hz; +register_current_timer_delay (&msm_delay_timer); }#ifdef CONFIG_ARCH_QCOM
Signature · 1 line
1.7.9.5
PATCH 61/71 clocksource: sh_tmu: Fix channel IRQ retrieval in legacy case
In reply to Daniel LezcanoFrom: Laurent Pinchart <[email protected]>
In the legacy platform data case each TMU platform device handles a single channel with a single IRQ for the platform device. Retrieve the IRQ using the logical channel number instead of the hardware channel number.
--- drivers/clocksource/sh_tmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/sh_tmu.c +1 -1
@@ -498,7 +498,7 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index, ch->base = tmu->mapbase +8 + ch->index *12 ; } - ch->irq =platform_get_irq (tmu->pdev, ch->index); + ch->irq =platform_get_irq (tmu->pdev, index);if (ch->irq <0 ) {dev_err (&tmu->pdev->dev,"ch%u: failed to get irq\n" , ch->index);
Signature · 1 line
1.7.9.5
PATCH 62/71 clocksource: Fix type confusion for clocksource_mmio_readX_Y
In reply to Daniel LezcanoFrom: Xiubo Li <[email protected]>
The types' definations are:
o cycle_t -> u64 o readl_relaxed -> u32 o readw_relaxed -> u16
So let clocksource_mmio_readX_Ys return a cast to cycle_t, though this maybe look reduntant sometimes, it make sense and they will be more readable and less confusion...
This patch clarifies the functions type and fix it.
--- drivers/clocksource/mmio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/clocksource/mmio.c +4 -4
@@ -22,22 +22,22 @@ static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)cycle_t clocksource_mmio_readl_up (struct clocksource *c) { -return readl_relaxed (to_mmio_clksrc (c)->reg); +return (cycle_t )readl_relaxed (to_mmio_clksrc (c)->reg); }cycle_t clocksource_mmio_readl_down (struct clocksource *c) { -return ~readl_relaxed (to_mmio_clksrc (c)->reg); +return ~(cycle_t )readl_relaxed (to_mmio_clksrc (c)->reg); }cycle_t clocksource_mmio_readw_up (struct clocksource *c) { -return readw_relaxed (to_mmio_clksrc (c)->reg); +return (cycle_t )readw_relaxed (to_mmio_clksrc (c)->reg); }cycle_t clocksource_mmio_readw_down (struct clocksource *c) { -return ~(unsigned )readw_relaxed (to_mmio_clksrc (c)->reg); +return ~(cycle_t )readw_relaxed (to_mmio_clksrc (c)->reg); }/**
Signature · 1 line
1.7.9.5
PATCH 63/71 clocksource: Fix clocksource_mmio_readX_down
In reply to Daniel LezcanoFrom: Xiubo Li <[email protected]>
For some clocksource devices, for example, the registers are 32-bit, while the lower 16-bit is used for timer counting(And reading the upper 16-bit will return 0).
For example, when the counter value is 0x00001111, and then the ~readl_relaxed(to_mmio_clksrc(c)->reg) will return the value of 0xFFFFEEEE, but it should be 0x0000EEEE.
So just using the c->mask to mask the unused bits.
--- drivers/clocksource/mmio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/mmio.c +2 -2
@@ -27,7 +27,7 @@ cycle_t clocksource_mmio_readl_up(struct clocksource *c)cycle_t clocksource_mmio_readl_down (struct clocksource *c) { -return ~(cycle_t )readl_relaxed (to_mmio_clksrc (c)->reg); +return ~(cycle_t )readl_relaxed (to_mmio_clksrc (c)->reg) & c->mask; }cycle_t clocksource_mmio_readw_up (struct clocksource *c)
@@ -37,7 +37,7 @@ cycle_t clocksource_mmio_readw_up(struct clocksource *c)cycle_t clocksource_mmio_readw_down (struct clocksource *c) { -return ~(cycle_t )readw_relaxed (to_mmio_clksrc (c)->reg); +return ~(cycle_t )readw_relaxed (to_mmio_clksrc (c)->reg) & c->mask; }/**
Signature · 1 line
1.7.9.5
PATCH 64/71 clocksource: dw_apb_timer_of: Do not trace read_sched_clock
In reply to Daniel LezcanoFrom: Yang Wei <[email protected]>
We do not need to trace read_sched_clock function, so add notrace attribute for this function.
--- drivers/clocksource/dw_apb_timer_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/dw_apb_timer_of.c +1 -1
@@ -106,7 +106,7 @@ static void __init add_clocksource(struct device_node *source_timer) sched_rate = rate; } -static u64 read_sched_clock (void ) +static u64 notrace read_sched_clock(void) {return ~__raw_readl (sched_io_base); }
Signature · 1 line
1.7.9.5
PATCH 65/71 clocksource: em_sti: Remove unnecessary OOM messages
In reply to Daniel LezcanoFrom: Jingoo Han <[email protected]>
The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message.
--- drivers/clocksource/em_sti.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/clocksource/em_sti.c +1 -3
@@ -318,10 +318,8 @@ static int em_sti_probe(struct platform_device *pdev)int irq; p =devm_kzalloc (&pdev->dev,sizeof (*p),GFP_KERNEL ); -if (p ==NULL ) { -dev_err (&pdev->dev,"failed to allocate driver data\n" ); +if (p ==NULL )return -ENOMEM ; - } p->pdev = pdev;platform_set_drvdata (pdev, p);
Signature · 1 line
1.7.9.5
PATCH 66/71 clocksource: sh_cmt: Remove unnecessary OOM messages
In reply to Daniel LezcanoFrom: Jingoo Han <[email protected]>
The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message.
[dlezcano] : refreshed against latest modifications: kmalloc -> kzalloc
--- drivers/clocksource/sh_cmt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/clocksource/sh_cmt.c +1 -3
@@ -1106,10 +1106,8 @@ static int sh_cmt_probe(struct platform_device *pdev) } cmt =kzalloc (sizeof (*cmt),GFP_KERNEL ); -if (cmt ==NULL ) { -dev_err (&pdev->dev,"failed to allocate driver data\n" ); +if (cmt ==NULL )return -ENOMEM ; - } ret =sh_cmt_setup (cmt, pdev);if (ret) {
Signature · 1 line
1.7.9.5
PATCH 67/71 clocksource: sh_mtu2: Remove unnecessary OOM messages
In reply to Daniel LezcanoFrom: Jingoo Han <[email protected]>
The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message.
[dlezcano] : refreshed against latest modifications: kmalloc -> kzalloc
--- drivers/clocksource/sh_mtu2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/clocksource/sh_mtu2.c +1 -3
@@ -533,10 +533,8 @@ static int sh_mtu2_probe(struct platform_device *pdev) } mtu =kzalloc (sizeof (*mtu),GFP_KERNEL ); -if (mtu ==NULL ) { -dev_err (&pdev->dev,"failed to allocate driver data\n" ); +if (mtu ==NULL )return -ENOMEM ; - } ret =sh_mtu2_setup (mtu, pdev);if (ret) {
Signature · 1 line
1.7.9.5
PATCH 68/71 clocksource: sh_tmu: Remove unnecessary OOM messages
In reply to Daniel LezcanoFrom: Jingoo Han <[email protected]>
The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message.
[dlezcano] : refreshed against latest modifications: kmalloc -> kzalloc
--- drivers/clocksource/sh_tmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/clocksource/sh_tmu.c +1 -3
@@ -644,10 +644,8 @@ static int sh_tmu_probe(struct platform_device *pdev) } tmu =kzalloc (sizeof (*tmu),GFP_KERNEL ); -if (tmu ==NULL ) { -dev_err (&pdev->dev,"failed to allocate driver data\n" ); +if (tmu ==NULL )return -ENOMEM ; - } ret =sh_tmu_setup (tmu, pdev);if (ret) {
Signature · 1 line
1.7.9.5
PATCH 69/71 clocksource: ftm: Add FlexTimer Module (FTM) Timer devicetree Documentation
In reply to Daniel LezcanoFrom: Xiubo Li <[email protected]>
The FTM binding could be used on Vybrid and LS1+, add a binding document for it.
--- .../devicetree/bindings/timer/fsl,ftm-timer.txt | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt
Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt new file +31 -0
@@ -0,0 +1,31 @@ +Freescale FlexTimer Module (FTM) Timer + +Required properties: + +- compatible : should be "fsl,ftm-timer" +- reg : Specifies base physical address and size of the register sets for the + clock event device and clock source device. +- interrupts : Should be the clock event device interrupt. +- clocks : The clocks provided by the SoC to drive the timer, must contain an + entry for each entry in clock-names. +- clock-names : Must include the following entries: + o "ftm-evt" + o "ftm-src" + o "ftm-evt-counter-en" + o "ftm-src-counter-en" +- big-endian: One boolean property, the big endian mode will be in use if it is + present, or the little endian mode will be in use for all the device registers. + +Example: +ftm: ftm at 400b8000 { + compatible = "fsl,ftm-timer"; + reg = <0x400b8000 0x1000 0x400b9000 0x1000>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "ftm-evt", "ftm-src", + "ftm-evt-counter-en", "ftm-src-counter-en"; + clocks = <&clks VF610_CLK_FTM2>, + <&clks VF610_CLK_FTM3>, + <&clks VF610_CLK_FTM2_EXT_FIX_EN>, + <&clks VF610_CLK_FTM3_EXT_FIX_EN>; + big-endian; +};
Signature · 1 line
1.7.9.5
PATCH 70/71 ARM: dts: vf610: Add Freescale FlexTimer Module timer node.
In reply to Daniel LezcanoFrom: Xiubo Li <[email protected]>
--- arch/arm/boot/dts/vf610.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/arm/boot/dts/vf610.dtsi +13 -0
@@ -347,6 +347,19 @@ status = "disabled"; }; + ftm: ftm at 400b8000 { + compatible = "fsl,ftm-timer"; + reg = <0x400b8000 0x1000 0x400b9000 0x1000>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "ftm-evt", "ftm-src", + "ftm-evt-counter-en", "ftm-src-counter-en"; + clocks = <&clks VF610_CLK_FTM2>, + <&clks VF610_CLK_FTM3>, + <&clks VF610_CLK_FTM2_EXT_FIX_EN>, + <&clks VF610_CLK_FTM3_EXT_FIX_EN>; + status = "disabled"; + }; + fec0: ethernet at 400d0000 { compatible = "fsl,mvf600-fec"; reg = <0x400d0000 0x1000>;
Signature · 1 line
1.7.9.5
PATCH 71/71 clocksource: Add Freescale FlexTimer Module (FTM) timer support
In reply to Daniel LezcanoFrom: Xiubo Li <[email protected]>
The Freescale FlexTimer Module time reference is a 16-bit counter that can be used as an unsigned or signed increase counter.
CNTIN defines the starting value of the count and MOD defines the final value of the count. The value of CNTIN is loaded into the FTM counter, and the counter increments until the value of MOD is reached, at which point the counter is reloaded with the value of CNTIN. That's also when an overflow interrupt will be generated.
Here using the 'evt' prefix or postfix as clock event device and the 'src' as clock source device.
--- drivers/clocksource/Kconfig | 5 + drivers/clocksource/Makefile | 1 + drivers/clocksource/fsl_ftm_timer.c | 367 +++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 drivers/clocksource/fsl_ftm_timer.c
drivers/clocksource/Kconfig +5 -0
@@ -136,6 +136,11 @@ config CLKSRC_SAMSUNG_PWM for all devicetree enabled platforms. This driver will be needed only on systems that do not have the Exynos MCT available. +config FSL_FTM_TIMER + bool + help + Support for Freescale FlexTimer Module (FTM) timer. + config VF_PIT_TIMER bool help
drivers/clocksource/Makefile +1 -0
@@ -31,6 +31,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o +obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
drivers/clocksource/fsl_ftm_timer.c new file +367 -0
367 lines not on this page · raw message
Signature · 1 line
1.7.9.5
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 7 lines · Stephen Rothwell
Hi all,
Quoted 2 lines · On Fri, 23 May 2014 12:22:04 +0200 Daniel Lezcano <[email protected]>…
clocksource: sun5i: Add support for reset controller
This commit caused a build failure on arm in linux-next today ...
Thanks Stephen.
Maxime ?
Signature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Quoted 8 lines · Daniel Lezcano
Quoted 7 lines · Stephen Rothwell
Hi all,
Quoted 2 lines · On Fri, 23 May 2014 12:22:04 +0200 Daniel Lezcano <[email protected]>…
clocksource: sun5i: Add support for reset controller
This commit caused a build failure on arm in linux-next today ...
It's weird... of_reset_control_get has been merged in 3.15 by this commit fc0a5921561c71be2c334a335c1680f7930434d7 ("reset: Add of_reset_control_get"), and then the commit b424080a9e086e683ad5fdc624a7cf3c024e0c0f ("reset: Add optional resets and stubs") removed it, still in 3.15 (probably a mismerge).
Finally, Hans de Goede introduced it back in the following patch:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/246738.html
That should have shown up in one of 3.15-rc's according to:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/252317.html
Philipp, what's going on?
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140526/3d498f0f/attachment.sig>
Hi Maxime,
Am Montag, den 26.05.2014, 15:40 +0200 schrieb Maxime Ripard:
Quoted 16 lines · Daniel Lezcano
Quoted 8 lines · Stephen Rothwell
Quoted 7 lines
Hi all,
Quoted 2 lines · On Fri, 23 May 2014 12:22:04 +0200 Daniel Lezcano <[email protected]>…
clocksource: sun5i: Add support for reset controller
This commit caused a build failure on arm in linux-next today ...
It's weird...
of_reset_control_gethas been merged in 3.15 by this commitfc0a5921561c71be2c334a335c1680f7930434d7("reset: Addof_reset_control_get"), and then the commitb424080a9e086e683ad5fdc624a7cf3c024e0c0f("reset: Add optional resets and stubs") removed it, still in 3.15 (probably a mismerge).
Quoted 7 lines
Finally, Hans de Goede introduced it back in the following patch:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/246738.htmlThat should have shown up in one of 3.15-rc's according to:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/252317.htmlPhilipp, what's going on?
I have sent a pull request now.
regards
Philipp