Skip to contentSkip to conversation

clockevents: new material for 3.16

GIT PULL New Daniel Lezcano 3 participants 75 messages May 23, 2014 – May 26, 2014 1 message not in the archive

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

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 the
dw_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.c
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
#1 lore raw

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
index 0b1836a..a3103b8 100644
@@ -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
#2 lore raw

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
index a3103b8..351b3ca 100644
@@ -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
#3 lore raw

PATCH 3/71 clocksource: sh_cmt: Rename struct sh_cmt_priv to sh_cmt_device

In reply to Daniel Lezcano

From: 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
index 351b3ca..604199a 100644
@@ -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
#4 lore raw

PATCH 4/71 clocksource: sh_cmt: Split channel setup to separate function

In reply to Daniel Lezcano

From: 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
index 604199a..26f73cf 100644
@@ -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
#5 lore raw

PATCH 5/71 clocksource: sh_cmt: Constify name argument to sh_cmt_register()

In reply to Daniel Lezcano

From: 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
index 26f73cf..febd6bf 100644
@@ -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
#6 lore raw

PATCH 6/71 clocksource: sh_cmt: Rename mapbase/mapbase_str to mapbase_ch/mapbase

In reply to Daniel Lezcano

From: 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
index febd6bf..eb93b88 100644
@@ -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
#7 lore raw

PATCH 7/71 clocksource: sh_cmt: Add memory base to sh_cmt_channel structure

In reply to Daniel Lezcano

From: 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
index eb93b88..4fcb05d 100644
@@ -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
#8 lore raw

PATCH 8/71 clocksource: sh_cmt: Add index to struct sh_cmt_channel

In reply to Daniel Lezcano

From: 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
index 4fcb05d..6b65621 100644
@@ -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
#9 lore raw

PATCH 9/71 clocksource: sh_cmt: Replace kmalloc + memset with kzalloc

In reply to Daniel Lezcano

From: 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
index 6b65621..0779bf1 100644
@@ -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
#10 lore raw

PATCH 10/71 clocksource: sh_cmt: Allocate channels dynamically

In reply to Daniel Lezcano

From: 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
index 0779bf1..f94db32 100644
@@ -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
#11 lore raw

PATCH 11/71 clocksource: sh_cmt: Split static information from sh_cmt_device

In reply to Daniel Lezcano

From: 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
index f94db32..879b8c2 100644
@@ -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
#12 lore raw

PATCH 12/71 clocksource: sh_cmt: Replace hardcoded register values with macros

In reply to Daniel Lezcano

From: 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
index 879b8c2..ce00baa 100644
@@ -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
#13 lore raw

PATCH 13/71 clocksource: sh_cmt: Set cpumask to cpu_possible_mask

In reply to Daniel Lezcano

From: 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
index ce00baa..926abe2 100644
@@ -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
#14 lore raw

PATCH 14/71 clocksource: sh_cmt: Hardcode CMT clock event rating to 125

In reply to Daniel Lezcano

From: 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
index 926abe2..75b1f83 100644
@@ -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
#15 lore raw

PATCH 15/71 clocksource: sh_cmt: Hardcode CMT clock source rating to 125

In reply to Daniel Lezcano

From: 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
index 75b1f83..c753efc 100644
@@ -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
#16 lore raw

PATCH 16/71 clocksource: sh_cmt: Add support for multiple channels per device

In reply to Daniel Lezcano

From: 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
index c753efc..1efe7d6 100644
@@ -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
index 4d9dcd1..8e1e036 100644
@@ -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
#17 lore raw

PATCH 17/71 clocksource: sh_cmt: Rename clock to "fck" in the non-legacy case

In reply to Daniel Lezcano

From: 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
index 1efe7d6..a5ea9ae 100644
@@ -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
#18 lore raw

PATCH 18/71 clocksource: sh_cmt: Remove FSF mail address from GPL notice

In reply to Daniel Lezcano

From: 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
index a5ea9ae..399e952 100644
@@ -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
#19 lore raw

PATCH 19/71 clocksource: sh_cmt: Sort headers alphabetically

In reply to Daniel Lezcano

From: 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
index 399e952..9f215e7 100644
@@ -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
#20 lore raw

PATCH 20/71 clocksource: sh_cmt: Request IRQ for clock event device only

In reply to Daniel Lezcano

From: 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
index 9f215e7..bc8d025 100644
@@ -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
#21 lore raw

PATCH 21/71 clocksource: sh_tmu: Use request_irq() instead of setup_irq()

In reply to Daniel Lezcano

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_tmu.c |   22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)
drivers/clocksource/sh_tmu.c +8 -14
index ecd7b60..8613cc9 100644
@@ -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
#22 lore raw

PATCH 22/71 clocksource: sh_tmu: Split channel fields from sh_tmu_priv

In reply to Daniel Lezcano

From: 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
index 8613cc9..26457e1 100644
@@ -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
#23 lore raw

PATCH 23/71 clocksource: sh_tmu: Rename struct sh_tmu_priv to sh_tmu_device

In reply to Daniel Lezcano

From: 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
index 26457e1..7013790 100644
@@ -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
#24 lore raw

PATCH 24/71 clocksource: sh_tmu: Split channel setup to separate function

In reply to Daniel Lezcano

From: 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
index 7013790..4779c97 100644
@@ -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
#25 lore raw

PATCH 25/71 clocksource: sh_tmu: Constify name argument to sh_tmu_register()

In reply to Daniel Lezcano

From: 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
index 4779c97..2c64e3f 100644
@@ -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
#26 lore raw

PATCH 26/71 clocksource: sh_tmu: Add memory base to sh_tmu_channel structure

In reply to Daniel Lezcano

From: 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
index 2c64e3f..a464ed8 100644
@@ -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
#27 lore raw

PATCH 27/71 clocksource: sh_tmu: Add index to struct sh_tmu_channel

In reply to Daniel Lezcano

From: 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
index a464ed8..e304304 100644
@@ -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
#28 lore raw

PATCH 28/71 clocksource: sh_tmu: Replace kmalloc + memset with kzalloc

In reply to Daniel Lezcano

From: 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
index e304304..26a9f7d 100644
@@ -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
#29 lore raw

PATCH 29/71 clocksource: sh_tmu: Allocate channels dynamically

In reply to Daniel Lezcano

From: 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
index 26a9f7d..55b7a37 100644
@@ -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
#30 lore raw

PATCH 30/71 clocksource: sh_tmu: Replace hardcoded register values with macros

In reply to Daniel Lezcano

From: 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
index 55b7a37..63ed92d 100644
@@ -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
#31 lore raw

PATCH 31/71 clocksource: sh_tmu: Hardcode TMU clock event and source ratings to 200

In reply to Daniel Lezcano

From: 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
index 63ed92d..fec9bed 100644
@@ -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
#32 lore raw

PATCH 32/71 clocksource: sh_tmu: Add support for multiple channels per device

In reply to Daniel Lezcano

From: 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
index fec9bed..0306d31 100644
@@ -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
#33 lore raw

PATCH 33/71 clocksource: sh_tmu: Rename clock to "fck" in the non-legacy case

In reply to Daniel Lezcano

From: 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
index 0306d31..cf07797 100644
@@ -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
#34 lore raw

PATCH 34/71 clocksource: sh_tmu: Remove FSF mail address from GPL notice

In reply to Daniel Lezcano

From: 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
index cf07797..981f8d3 100644
@@ -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
#35 lore raw

PATCH 35/71 clocksource: sh_tmu: Sort headers alphabetically

In reply to Daniel Lezcano

From: 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
index 981f8d3..4ba2c0f 100644
@@ -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
#36 lore raw

PATCH 36/71 clocksource: sh_mtu2: Use request_irq() instead of setup_irq()

In reply to Daniel Lezcano

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_mtu2.c |   22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)
drivers/clocksource/sh_mtu2.c +8 -14
index e30d76e..77992e0 100644
@@ -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
#37 lore raw

PATCH 37/71 clocksource: sh_mtu2: Turn sh_mtu2_priv fields into local variables

In reply to Daniel Lezcano

From: 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
index 77992e0..6668455 100644
@@ -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
#38 lore raw

PATCH 38/71 clocksource: sh_mtu2: Split channel fields from sh_mtu2_priv

In reply to Daniel Lezcano

From: 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
index 6668455..e509f41 100644
@@ -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
#39 lore raw

PATCH 39/71 clocksource: sh_mtu2: Rename struct sh_mtu2_priv to sh_mtu2_device

In reply to Daniel Lezcano

From: 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
index e509f41..256621c 100644
@@ -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
#40 lore raw

PATCH 40/71 clocksource: sh_mtu2: Split channel setup to separate function

In reply to Daniel Lezcano

From: 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
index 256621c..8fd7059 100644
@@ -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
#41 lore raw

PATCH 41/71 clocksource: sh_mtu2: Constify name argument to sh_mtu2_register()

In reply to Daniel Lezcano

From: 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
index 8fd7059..2fe3ab4c 100644
@@ -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
#42 lore raw

PATCH 42/71 clocksource: sh_mtu2: Add memory base to sh_mtu2_channel structure

In reply to Daniel Lezcano

From: 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
index 2fe3ab4c..97714ce 100644
@@ -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
#43 lore raw

PATCH 43/71 clocksource: sh_mtu2: Add index to struct sh_mtu2_channel

In reply to Daniel Lezcano

From: 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
index 97714ce..61827c6 100644
@@ -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
#44 lore raw

PATCH 44/71 clocksource: sh_mtu2: Replace kmalloc + memset with kzalloc

In reply to Daniel Lezcano

From: 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
index 61827c6..94a5342 100644
@@ -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
#45 lore raw

PATCH 45/71 clocksource: sh_mtu2: Allocate channels dynamically

In reply to Daniel Lezcano

From: 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
index 94a5342..45e1e85 100644
@@ -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
#46 lore raw

PATCH 46/71 clocksource: sh_mtu2: Replace hardcoded register values with macros

In reply to Daniel Lezcano

From: 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
index 45e1e85..2cf0048 100644
@@ -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
#47 lore raw

PATCH 47/71 clocksource: sh_mtu2: Set cpumask to cpu_possible_mask

In reply to Daniel Lezcano

From: 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
index 2cf0048..702ce60 100644
@@ -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
#48 lore raw

PATCH 48/71 clocksource: sh_mtu2: Hardcode MTU2 clock event rating to 200

In reply to Daniel Lezcano

From: 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
index 702ce60..14cc7b6 100644
@@ -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
#49 lore raw

PATCH 49/71 clocksource: sh_mtu2: Add support for multiple channels per device

In reply to Daniel Lezcano

From: 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
index 14cc7b6..7cc6d942 100644
@@ -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
#50 lore raw

PATCH 50/71 clocksource: sh_mtu2: Rename clock to "fck" in the non-legacy case

In reply to Daniel Lezcano

From: 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
index 7cc6d942..3a37857 100644
@@ -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
#51 lore raw

PATCH 51/71 clocksource: sh_mtu2: Remove FSF mail address from GPL notice

In reply to Daniel Lezcano

From: 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
index 3a37857..510bd32 100644
@@ -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
#52 lore raw

PATCH 52/71 clocksource: sh_mtu2: Sort headers alphabetically

In reply to Daniel Lezcano

From: 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
index 510bd32..f2c1c36 100644
@@ -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
#53 lore raw

PATCH 53/71 clocksource: arm_global_timer: Only check for unusable timer on A9

In reply to Daniel Lezcano

From: 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
index 0fc31d0..60e5a170 100644
@@ -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
#54 lore raw

PATCH 54/71 documentaion: DT: allow a A5 compatible string in global timer

In reply to Daniel Lezcano

From: 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
index 1e54898..bdae3a8 100644
@@ -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
#55 lore raw

PATCH 55/71 dts: ca5: add the global timer for the A5

In reply to Daniel Lezcano

From: 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
index c544a55..d2709b7 100644
@@ -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
#56 lore raw

PATCH 56/71 KConfig: Vexpress: build the ARM_GLOBAL_TIMER with vexpress platform

In reply to Daniel Lezcano

From: 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
index 657d52d..e9811a0 100644
@@ -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
#57 lore raw

PATCH 57/71 clocksource: efm32: use $vendor,$device scheme for compatible string

In reply to Daniel Lezcano

From: 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
deleted file mode 100644
index 97a568f..0000000
@@ -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
new file mode 100644
index 0000000..e502c11
@@ -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
index 1a6205b..bba62f9 100644
@@ -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
#58 lore raw

PATCH 58/71 clocksource: sun5i: Add support for reset controller

In reply to Daniel Lezcano

From: 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
index 7c26154..27cfc7d 100644
@@ -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
index deebcd6..0226844 100644
@@ -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
#59 lore raw

PATCH 59/71 ARM: sun6i: a31: Add support for the High Speed Timers

In reply to Daniel Lezcano

From: 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
index d45efa7..8cee8a1 100644
@@ -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
#60 lore raw

PATCH 60/71 clocksource: qcom: Implement read_current_timer for udelay

In reply to Daniel Lezcano

From: 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
index e807acf..8d115db 100644
@@ -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
#61 lore raw

PATCH 61/71 clocksource: sh_tmu: Fix channel IRQ retrieval in legacy case

In reply to Daniel Lezcano

From: 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
index 4ba2c0f..ec34095 100644
@@ -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
#62 lore raw

PATCH 62/71 clocksource: Fix type confusion for clocksource_mmio_readX_Y

In reply to Daniel Lezcano

From: 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
index c0e2512..19a6b3f 100644
@@ -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
#63 lore raw

PATCH 63/71 clocksource: Fix clocksource_mmio_readX_down

In reply to Daniel Lezcano

From: 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
index 19a6b3f..1593ade 100644
@@ -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
#64 lore raw

PATCH 64/71 clocksource: dw_apb_timer_of: Do not trace read_sched_clock

In reply to Daniel Lezcano

From: 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
index 2a2ea27..d305fb0 100644
@@ -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
#65 lore raw

PATCH 65/71 clocksource: em_sti: Remove unnecessary OOM messages

In reply to Daniel Lezcano

From: 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
index 9d17083..d0a7bd6 100644
@@ -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
#66 lore raw

PATCH 66/71 clocksource: sh_cmt: Remove unnecessary OOM messages

In reply to Daniel Lezcano

From: 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
index bc8d025..dfa7803 100644
@@ -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
#67 lore raw

PATCH 67/71 clocksource: sh_mtu2: Remove unnecessary OOM messages

In reply to Daniel Lezcano

From: 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
index f2c1c36..188d4e0 100644
@@ -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
#68 lore raw

PATCH 68/71 clocksource: sh_tmu: Remove unnecessary OOM messages

In reply to Daniel Lezcano

From: 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
index 4ba2c0f..a38022f 100644
@@ -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
#69 lore raw

PATCH 69/71 clocksource: ftm: Add FlexTimer Module (FTM) Timer devicetree Documentation

In reply to Daniel Lezcano

From: 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
new file mode 100644
index 0000000..aa8c402
@@ -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
#70 lore raw

PATCH 70/71 ARM: dts: vf610: Add Freescale FlexTimer Module timer node.

In reply to Daniel Lezcano

From: Xiubo Li <[email protected]>

---
 arch/arm/boot/dts/vf610.dtsi |   13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/vf610.dtsi +13 -0
index b8ce0aa7..3c91b84 100644
@@ -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
#71 lore raw

PATCH 71/71 clocksource: Add Freescale FlexTimer Module (FTM) timer support

In reply to Daniel Lezcano

From: 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
index 96918e1..0437767 100644
@@ -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
index 98cb6c5..0770916 100644
@@ -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]

#73 lore raw
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
#74 lore raw
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>
#75 lore raw

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_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).

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.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?

I have sent a pull request now.

regards
Philipp