2012-05-09 14:38:36

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 00/03] clocksource: Emma Mobile STI V2 patches

clocksource: Emma Mobile STI V2 patches

[PATCH 01/03] clockevents: Make clockevents_config() a global symbol
[PATCH 02/03] clocksource: em_sti: Emma Mobile STI driver V2
[PATCH 03/03] clocksource: em_sti: Add DT support

This is the second version of Emma Mobile STI driver. Now with
significantly cleaner clockevent intergration and DT support.

The driver is implemented as a regular platform device which makes
use of the STI hardware and provides both clocksource and clockevent
interfaces with a single 48-bit hardware counter.

It is worth mentioning that the driver makes use of clockevents_config()
to update the timer frequency after registration time. This is done to
save power by making sure that unused timer hardware is stopped whenever
possible.

The reason behind allowing the driver to use clockevents_config() is in
detail as follows. The clock associated with the timer gets enabled when
starting the clocksource/clockevent and it gets disabled when the
clocksource or clockevent gets stopped. Due to the design of the clock
framework the rate of the clock is only known after the clock has been
enabled. And to save power the clock is only enabled when it is known
that it will be used - and to know that the clocksource/clockevent needs
to be registered first. This in turn means that we are unaware of the
frequency at registration time. Which leads to that it is not sufficient
to use a fixed frequency at registration time but we must instead make
sure the frequency is updated after each clk_enable().

Many thanks to Thomas Gleixner for very useful V1 feedback.

Signed-off-by: Magnus Damm <[email protected]>
---

arch/arm/mach-shmobile/Kconfig | 12
drivers/clocksource/Makefile | 2
drivers/clocksource/em_sti.c | 843 ++++++++++++++++++++++++++++++++++++++++
include/linux/clockchips.h | 1
kernel/time/clockevents.c | 3
5 files changed, 859 insertions(+), 2 deletions(-)


2012-05-09 14:38:42

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 01/03] clockevents: Make clockevents_config() a global symbol

From: Magnus Damm <[email protected]>

Make clockevents_config() into a global symbol to allow it
to be used by compiled-in clockevent drivers. This is needed
by drivers that want to update the timer frequency after
registration time.

Signed-off-by: Magnus Damm <[email protected]>
---

include/linux/clockchips.h | 1 +
kernel/time/clockevents.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)

--- 0001/include/linux/clockchips.h
+++ work/include/linux/clockchips.h 2012-05-09 22:43:41.000000000 +0900
@@ -132,6 +132,7 @@ extern u64 clockevent_delta2ns(unsigned
struct clock_event_device *evt);
extern void clockevents_register_device(struct clock_event_device *dev);

+extern void clockevents_config(struct clock_event_device *dev, u32 freq);
extern void clockevents_config_and_register(struct clock_event_device *dev,
u32 freq, unsigned long min_delta,
unsigned long max_delta);
--- 0001/kernel/time/clockevents.c
+++ work/kernel/time/clockevents.c 2012-05-09 22:48:39.000000000 +0900
@@ -297,8 +297,7 @@ void clockevents_register_device(struct
}
EXPORT_SYMBOL_GPL(clockevents_register_device);

-static void clockevents_config(struct clock_event_device *dev,
- u32 freq)
+void clockevents_config(struct clock_event_device *dev, u32 freq)
{
u64 sec;

2012-05-09 14:38:51

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 02/03] clocksource: em_sti: Emma Mobile STI driver V2

From: Magnus Damm <[email protected]>

This is V2 of the Emma Mobile STI timer driver.

The STI hardware is based on a single 48-bit 32kHz
counter that together with two individual compare
registers can generate interrupts. There are no
timer operating modes selectable which means that
the timer can not clear on match.

This driver is providing clocksource support for the
48-bit counter. Clockevents are also supported using
the same timer in periodic or oneshot modes.

Signed-off-by: Magnus Damm <[email protected]>
---

Changes since V1 :
- removed unused early timer cruft
- reduce number of functions
- use request_irq() instead setup_irq() since we run late during boot
- replace confusing flags with perhaps equally confusing active[] array
- use clockevents_config_and_register() for registration
- update frequency with clockevents_config()
- use 2 ticks as minimum
- verify oneshot timer and return error to clock event layer

Verified in the following modes on EMEV2:
- clocksource only
- clockevent in periodic mode only
- clocksource and clockevent in periodic mode
- clocksource and clockevent in oneshot mode

arch/arm/mach-shmobile/Kconfig | 6
drivers/clocksource/Makefile | 1
drivers/clocksource/em_sti.c | 418 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 425 insertions(+)

--- 0013/arch/arm/mach-shmobile/Kconfig
+++ work/arch/arm/mach-shmobile/Kconfig 2012-05-09 22:44:52.000000000 +0900
@@ -168,6 +168,12 @@ config SH_TIMER_TMU
help
This enables build of the TMU timer driver.

+config EM_TIMER_STI
+ bool "STI timer driver"
+ default y
+ help
+ This enables build of the STI timer driver.
+
endmenu

config SH_CLK_CPG
--- 0001/drivers/clocksource/Makefile
+++ work/drivers/clocksource/Makefile 2012-05-09 22:44:52.000000000 +0900
@@ -6,6 +6,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) +=
obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o
obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o
obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
+obj-$(CONFIG_EM_TIMER_STI) += em_sti.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
--- /dev/null
+++ work/drivers/clocksource/em_sti.c 2012-05-09 22:44:52.000000000 +0900
@@ -0,0 +1,418 @@
+/*
+ * Emma Mobile Timer Support - STI
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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>
+#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/irq.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+enum { USER_CLOCKSOURCE, USER_CLOCKEVENT, USER_NR };
+
+struct em_sti_priv {
+ void __iomem *base;
+ struct clk *clk;
+ struct platform_device *pdev;
+ unsigned int active[USER_NR];
+ unsigned long rate;
+ unsigned long delta;
+ cycle_t next;
+ spinlock_t lock;
+ struct clock_event_device ced;
+ struct clocksource cs;
+};
+
+#define STI_CONTROL 0x00
+#define STI_COMPA_H 0x10
+#define STI_COMPA_L 0x14
+#define STI_COMPB_H 0x18
+#define STI_COMPB_L 0x1c
+#define STI_COUNT_H 0x20
+#define STI_COUNT_L 0x24
+#define STI_COUNT_RAW_H 0x28
+#define STI_COUNT_RAW_L 0x2c
+#define STI_SET_H 0x30
+#define STI_SET_L 0x34
+#define STI_INTSTATUS 0x40
+#define STI_INTRAWSTATUS 0x44
+#define STI_INTENSET 0x48
+#define STI_INTENCLR 0x4c
+#define STI_INTFFCLR 0x50
+
+static inline unsigned long em_sti_read(struct em_sti_priv *p, int offs)
+{
+ return ioread32(p->base + offs);
+}
+
+static inline void em_sti_write(struct em_sti_priv *p, int offs,
+ unsigned long value)
+{
+ iowrite32(value, p->base + offs);
+}
+
+static int em_sti_enable(struct em_sti_priv *p)
+{
+ int ret;
+
+ /* enable clock */
+ ret = clk_enable(p->clk);
+ if (ret) {
+ dev_err(&p->pdev->dev, "cannot enable clock\n");
+ return ret;
+ }
+
+ /* configure channel, periodic mode and maximum timeout */
+ p->rate = clk_get_rate(p->clk);
+
+ /* reset the counter */
+ em_sti_write(p, STI_SET_H, 0x40000000);
+ em_sti_write(p, STI_SET_L, 0x00000000);
+
+ /* mask and clear pending interrupts */
+ em_sti_write(p, STI_INTENCLR, 3);
+ em_sti_write(p, STI_INTFFCLR, 3);
+
+ /* enable updates of counter registers */
+ em_sti_write(p, STI_CONTROL, 1);
+
+ return 0;
+}
+
+static void em_sti_disable(struct em_sti_priv *p)
+{
+ /* mask interrupts */
+ em_sti_write(p, STI_INTENCLR, 3);
+
+ /* stop clock */
+ clk_disable(p->clk);
+}
+
+static cycle_t em_sti_count(struct em_sti_priv *p)
+{
+ cycle_t ticks;
+ unsigned long flags;
+
+ /* the STI hardware buffers the 48-bit count, but to
+ * break it out into two 32-bit access the registers
+ * must be accessed in a certain order.
+ * Always read STI_COUNT_H before STI_COUNT_L.
+ */
+ spin_lock_irqsave(&p->lock, flags);
+ ticks = (cycle_t)(em_sti_read(p, STI_COUNT_H) & 0xffff) << 32;
+ ticks |= em_sti_read(p, STI_COUNT_L);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return ticks;
+}
+
+static void em_sti_update(struct em_sti_priv *p)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* update our cached counter */
+ p->next += p->delta;
+
+ /* mask compare A interrupt */
+ em_sti_write(p, STI_INTENCLR, 1);
+
+ /* update compare A value */
+ em_sti_write(p, STI_COMPA_H, p->next >> 32);
+ em_sti_write(p, STI_COMPA_L, p->next & 0xffffffff);
+
+ /* clear compare A interrupt source */
+ em_sti_write(p, STI_INTFFCLR, 1);
+
+ /* unmask compare A interrupt */
+ em_sti_write(p, STI_INTENSET, 1);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static irqreturn_t em_sti_interrupt(int irq, void *dev_id)
+{
+ struct em_sti_priv *p = dev_id;
+
+ /* Always regprogram timer compare A */
+ if (p->ced.mode == CLOCK_EVT_MODE_PERIODIC)
+ em_sti_update(p);
+
+ p->ced.event_handler(&p->ced);
+ return IRQ_HANDLED;
+}
+
+static int em_sti_start(struct em_sti_priv *p, unsigned int user)
+{
+ unsigned long flags;
+ int used_before;
+ int ret = 0;
+
+ spin_lock_irqsave(&p->lock, flags);
+ used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
+ if (!used_before)
+ ret = em_sti_enable(p);
+
+ if (!ret)
+ p->active[user] = 1;
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return ret;
+}
+
+static void em_sti_stop(struct em_sti_priv *p, unsigned int user)
+{
+ unsigned long flags;
+ int used_before, used_after;
+
+ spin_lock_irqsave(&p->lock, flags);
+ used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
+ p->active[user] = 0;
+ used_after = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
+
+ if (used_before && !used_after)
+ em_sti_disable(p);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static struct em_sti_priv *cs_to_em_sti(struct clocksource *cs)
+{
+ return container_of(cs, struct em_sti_priv, cs);
+}
+
+static cycle_t em_sti_clocksource_read(struct clocksource *cs)
+{
+ return em_sti_count(cs_to_em_sti(cs));
+}
+
+static int em_sti_clocksource_enable(struct clocksource *cs)
+{
+ int ret;
+ struct em_sti_priv *p = cs_to_em_sti(cs);
+
+ ret = em_sti_start(p, USER_CLOCKSOURCE);
+ if (!ret)
+ __clocksource_updatefreq_hz(cs, p->rate);
+ return ret;
+}
+
+static void em_sti_clocksource_disable(struct clocksource *cs)
+{
+ em_sti_stop(cs_to_em_sti(cs), USER_CLOCKSOURCE);
+}
+
+static void em_sti_clocksource_resume(struct clocksource *cs)
+{
+ em_sti_clocksource_enable(cs);
+}
+
+static int em_sti_register_clocksource(struct em_sti_priv *p)
+{
+ struct clocksource *cs = &p->cs;
+
+ memset(cs, 0, sizeof(*cs));
+ cs->name = dev_name(&p->pdev->dev);
+ cs->rating = 200;
+ cs->read = em_sti_clocksource_read;
+ cs->enable = em_sti_clocksource_enable;
+ cs->disable = em_sti_clocksource_disable;
+ cs->suspend = em_sti_clocksource_disable;
+ cs->resume = em_sti_clocksource_resume;
+ cs->mask = CLOCKSOURCE_MASK(48);
+ cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ dev_info(&p->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 em_sti_priv *ced_to_em_sti(struct clock_event_device *ced)
+{
+ return container_of(ced, struct em_sti_priv, ced);
+}
+
+static void em_sti_clock_event_mode(enum clock_event_mode mode,
+ struct clock_event_device *ced)
+{
+ struct em_sti_priv *p = ced_to_em_sti(ced);
+
+ /* deal with old setting first */
+ switch (ced->mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_ONESHOT:
+ em_sti_stop(p, USER_CLOCKEVENT);
+ break;
+ default:
+ break;
+ }
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ dev_info(&p->pdev->dev, "used for periodic clock events\n");
+ em_sti_start(p, USER_CLOCKEVENT);
+ clockevents_config(&p->ced, p->rate);
+ p->delta = (p->rate + HZ/2) / HZ;
+ p->next = em_sti_count(p);
+ em_sti_update(p);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ dev_info(&p->pdev->dev, "used for oneshot clock events\n");
+ em_sti_start(p, USER_CLOCKEVENT);
+ clockevents_config(&p->ced, p->rate);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ em_sti_stop(p, USER_CLOCKEVENT);
+ break;
+ default:
+ break;
+ }
+}
+
+static int em_sti_clock_event_next(unsigned long delta,
+ struct clock_event_device *ced)
+{
+ struct em_sti_priv *p = ced_to_em_sti(ced);
+ int safe;
+
+ p->delta = delta;
+ p->next = em_sti_count(p);
+ em_sti_update(p);
+
+ safe = em_sti_count(p) < (p->next - 1);
+
+ return !safe;
+}
+
+static void em_sti_register_clockevent(struct em_sti_priv *p)
+{
+ struct clock_event_device *ced = &p->ced;
+
+ memset(ced, 0, sizeof(*ced));
+ ced->name = dev_name(&p->pdev->dev);
+ ced->features = CLOCK_EVT_FEAT_PERIODIC;
+ ced->features |= CLOCK_EVT_FEAT_ONESHOT;
+ ced->rating = 200;
+ ced->cpumask = cpumask_of(0);
+ ced->set_next_event = em_sti_clock_event_next;
+ ced->set_mode = em_sti_clock_event_mode;
+
+ dev_info(&p->pdev->dev, "used for clock events\n");
+
+ /* Register with dummy 1 Hz value, gets updated in ->set_mode() */
+ clockevents_config_and_register(ced, 1, 2, 0xffffffff);
+}
+
+static int __devinit em_sti_probe(struct platform_device *pdev)
+{
+ struct em_sti_priv *p;
+ struct resource *res;
+ int irq, ret;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ /* map memory, let base point to the STI instance */
+ p->base = ioremap_nocache(res->start, resource_size(res));
+ if (p->base == NULL) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto err0;
+ }
+
+ /* get hold of clock */
+ p->clk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(p->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
+ }
+
+ if (request_irq(irq, em_sti_interrupt,
+ IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
+ dev_name(&pdev->dev), p)) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+ goto err2;
+ }
+
+ spin_lock_init(&p->lock);
+ em_sti_register_clockevent(p);
+ em_sti_register_clocksource(p);
+ return 0;
+
+err2:
+ clk_put(p->clk);
+err1:
+ iounmap(p->base);
+err0:
+ kfree(p);
+ return ret;
+}
+
+static int __devexit em_sti_remove(struct platform_device *pdev)
+{
+ return -EBUSY; /* cannot unregister clockevent and clocksource */
+}
+
+static struct platform_driver em_sti_device_driver = {
+ .probe = em_sti_probe,
+ .remove = __devexit_p(em_sti_remove),
+ .driver = {
+ .name = "em_sti",
+ }
+};
+
+module_platform_driver(em_sti_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver");
+MODULE_LICENSE("GPL v2");

2012-05-09 14:38:58

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 03/03] clocksource: em_sti: Add DT support

From: Magnus Damm <[email protected]>

Update the em-sti driver to support DT.

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/clocksource/em_sti.c | 7 +++++++
1 file changed, 7 insertions(+)

--- 0015/drivers/clocksource/em_sti.c
+++ work/drivers/clocksource/em_sti.c 2012-05-09 22:52:47.000000000 +0900
@@ -403,11 +403,18 @@ static int __devexit em_sti_remove(struc
return -EBUSY; /* cannot unregister clockevent and clocksource */
}

+static const struct of_device_id em_sti_dt_ids[] __devinitconst = {
+ { .compatible = "renesas,em-sti", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
+
static struct platform_driver em_sti_device_driver = {
.probe = em_sti_probe,
.remove = __devexit_p(em_sti_remove),
.driver = {
.name = "em_sti",
+ .of_match_table = em_sti_dt_ids,
}
};

2012-05-11 06:55:53

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH 00/03] clocksource: Emma Mobile STI V2 patches

On Wed, May 09, 2012 at 11:39:26PM +0900, Magnus Damm wrote:
> clocksource: Emma Mobile STI V2 patches
>
> [PATCH 01/03] clockevents: Make clockevents_config() a global symbol
> [PATCH 02/03] clocksource: em_sti: Emma Mobile STI driver V2

Patches 1 & 2.

Tested-by: Simon Horman <[email protected]>

> [PATCH 03/03] clocksource: em_sti: Add DT support

I am unsure how to exercise this code.

2012-05-23 06:33:23

by Paul Mundt

[permalink] [raw]
Subject: Re: [PATCH 01/03] clockevents: Make clockevents_config() a global symbol

On Wed, May 09, 2012 at 11:39:34PM +0900, Magnus Damm wrote:
> From: Magnus Damm <[email protected]>
>
> Make clockevents_config() into a global symbol to allow it
> to be used by compiled-in clockevent drivers. This is needed
> by drivers that want to update the timer frequency after
> registration time.
>
> Signed-off-by: Magnus Damm <[email protected]>

Any update on this?

2012-05-23 07:15:43

by Magnus Damm

[permalink] [raw]
Subject: Re: [PATCH 01/03] clockevents: Make clockevents_config() a global symbol

On Wed, May 23, 2012 at 3:32 PM, Paul Mundt <[email protected]> wrote:
> On Wed, May 09, 2012 at 11:39:34PM +0900, Magnus Damm wrote:
>> From: Magnus Damm <[email protected]>
>>
>> Make clockevents_config() into a global symbol to allow it
>> to be used by compiled-in clockevent drivers. This is needed
>> by drivers that want to update the timer frequency after
>> registration time.
>>
>> Signed-off-by: Magnus Damm <[email protected]>
>
> Any update on this?

Thanks, not from my side at least. I intend to resend the same series
later this week unless it gets picked up before that.

Cheers,

/ magnus

2012-05-24 10:27:24

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 01/03] clockevents: Make clockevents_config() a global symbol

On Wed, 23 May 2012, Paul Mundt wrote:

> On Wed, May 09, 2012 at 11:39:34PM +0900, Magnus Damm wrote:
> > From: Magnus Damm <[email protected]>
> >
> > Make clockevents_config() into a global symbol to allow it
> > to be used by compiled-in clockevent drivers. This is needed
> > by drivers that want to update the timer frequency after
> > registration time.
> >
> > Signed-off-by: Magnus Damm <[email protected]>
>
> Any update on this?

Ooops, I missed that. Can you take it through your tree with my
acked-by please?

Thanks,

tglx

2012-05-24 10:28:34

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 01/03] clockevents: Make clockevents_config() a global symbol

On Thu, 24 May 2012, Thomas Gleixner wrote:

> On Wed, 23 May 2012, Paul Mundt wrote:
>
> > On Wed, May 09, 2012 at 11:39:34PM +0900, Magnus Damm wrote:
> > > From: Magnus Damm <[email protected]>
> > >
> > > Make clockevents_config() into a global symbol to allow it
> > > to be used by compiled-in clockevent drivers. This is needed
> > > by drivers that want to update the timer frequency after
> > > registration time.
> > >
> > > Signed-off-by: Magnus Damm <[email protected]>
> >
> > Any update on this?
>
> Ooops, I missed that. Can you take it through your tree with my
> acked-by please?

Gah crap. I take the whole lot. Didn't notice that the driver is in
drivers/clocksource.

Sorry for the confusion.

2012-05-24 23:42:22

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 02/03] clocksource: em_sti: Emma Mobile STI driver V2

On Wed, 9 May 2012, Magnus Damm wrote:
> +static irqreturn_t em_sti_interrupt(int irq, void *dev_id)
> +{
> + struct em_sti_priv *p = dev_id;
> +
> + /* Always regprogram timer compare A */
> + if (p->ced.mode == CLOCK_EVT_MODE_PERIODIC)
> + em_sti_update(p);

Why do you want to do that? The core code already handles timers which
only support oneshot mode.

> + spin_lock_irqsave(&p->lock, flags);

Please make that a raw_spinlock.

> +static void em_sti_clock_event_mode(enum clock_event_mode mode,
> + struct clock_event_device *ced)
> +{
> + struct em_sti_priv *p = ced_to_em_sti(ced);
> +
> + /* deal with old setting first */
> + switch (ced->mode) {
> + case CLOCK_EVT_MODE_PERIODIC:
> + case CLOCK_EVT_MODE_ONESHOT:
> + em_sti_stop(p, USER_CLOCKEVENT);
> + break;
> + default:
> + break;
> + }
> +
> + switch (mode) {
> + case CLOCK_EVT_MODE_PERIODIC:
> + dev_info(&p->pdev->dev, "used for periodic clock events\n");
> + em_sti_start(p, USER_CLOCKEVENT);
> + clockevents_config(&p->ced, p->rate);
> + p->delta = (p->rate + HZ/2) / HZ;
> + p->next = em_sti_count(p);
> + em_sti_update(p);
> + break;

All that code in this case can go away.

> +static void em_sti_register_clockevent(struct em_sti_priv *p)
> +{
> + struct clock_event_device *ced = &p->ced;
> +
> + memset(ced, 0, sizeof(*ced));
> + ced->name = dev_name(&p->pdev->dev);
> + ced->features = CLOCK_EVT_FEAT_PERIODIC;
> + ced->features |= CLOCK_EVT_FEAT_ONESHOT;

If you make that:

ced->features = CLOCK_EVT_FEAT_ONESHOT;

Thanks,

tglx

2012-05-24 23:53:57

by Magnus Damm

[permalink] [raw]
Subject: [tip:timers/core] clockevents: Make clockevents_config() a global symbol

Commit-ID: e5400321a6f15ce0fe77c8455954f213ef7dcc54
Gitweb: http://git.kernel.org/tip/e5400321a6f15ce0fe77c8455954f213ef7dcc54
Author: Magnus Damm <[email protected]>
AuthorDate: Wed, 9 May 2012 23:39:34 +0900
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 25 May 2012 01:44:51 +0200

clockevents: Make clockevents_config() a global symbol

Make clockevents_config() into a global symbol to allow it to be used
by compiled-in clockevent drivers. This is needed by drivers that want
to update the timer frequency after registration time.

Signed-off-by: Magnus Damm <[email protected]>
Tested-by: Simon Horman <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: Magnus Damm <[email protected]>
Link: http://lkml.kernel.org/r/20120509143934.27521.46553.sendpatchset@w520
Signed-off-by: Thomas Gleixner <[email protected]>
---
include/linux/clockchips.h | 1 +
kernel/time/clockevents.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 81e803e..acba8943 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -132,6 +132,7 @@ extern u64 clockevent_delta2ns(unsigned long latch,
struct clock_event_device *evt);
extern void clockevents_register_device(struct clock_event_device *dev);

+extern void clockevents_config(struct clock_event_device *dev, u32 freq);
extern void clockevents_config_and_register(struct clock_event_device *dev,
u32 freq, unsigned long min_delta,
unsigned long max_delta);
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 9cd928f..7e1ce01 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -297,8 +297,7 @@ void clockevents_register_device(struct clock_event_device *dev)
}
EXPORT_SYMBOL_GPL(clockevents_register_device);

-static void clockevents_config(struct clock_event_device *dev,
- u32 freq)
+void clockevents_config(struct clock_event_device *dev, u32 freq)
{
u64 sec;

2012-05-25 03:39:10

by Magnus Damm

[permalink] [raw]
Subject: Re: [PATCH 02/03] clocksource: em_sti: Emma Mobile STI driver V2

Hi Thomas,

On Fri, May 25, 2012 at 8:42 AM, Thomas Gleixner <[email protected]> wrote:
> On Wed, 9 May 2012, Magnus Damm wrote:
>> +static irqreturn_t em_sti_interrupt(int irq, void *dev_id)
>> +{
>> + ? ? struct em_sti_priv *p = dev_id;
>> +
>> + ? ? /* Always regprogram timer compare A */
>> + ? ? if (p->ced.mode == CLOCK_EVT_MODE_PERIODIC)
>> + ? ? ? ? ? ? em_sti_update(p);
>
> Why do you want to do that? The core code already handles timers which
> only support oneshot mode.

Oh, I wasn't aware that oneshot only is a valid combination. Thanks
for pointing that out, the code will surely become cleaner!

>> + ? ? spin_lock_irqsave(&p->lock, flags);
>
> Please make that a raw_spinlock.

Ok!

>> +static void em_sti_clock_event_mode(enum clock_event_mode mode,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *ced)
>> +{
>> + ? ? struct em_sti_priv *p = ced_to_em_sti(ced);
>> +
>> + ? ? /* deal with old setting first */
>> + ? ? switch (ced->mode) {
>> + ? ? case CLOCK_EVT_MODE_PERIODIC:
>> + ? ? case CLOCK_EVT_MODE_ONESHOT:
>> + ? ? ? ? ? ? em_sti_stop(p, USER_CLOCKEVENT);
>> + ? ? ? ? ? ? break;
>> + ? ? default:
>> + ? ? ? ? ? ? break;
>> + ? ? }
>> +
>> + ? ? switch (mode) {
>> + ? ? case CLOCK_EVT_MODE_PERIODIC:
>> + ? ? ? ? ? ? dev_info(&p->pdev->dev, "used for periodic clock events\n");
>> + ? ? ? ? ? ? em_sti_start(p, USER_CLOCKEVENT);
>> + ? ? ? ? ? ? clockevents_config(&p->ced, p->rate);
>> + ? ? ? ? ? ? p->delta = (p->rate + HZ/2) / HZ;
>> + ? ? ? ? ? ? p->next = em_sti_count(p);
>> + ? ? ? ? ? ? em_sti_update(p);
>> + ? ? ? ? ? ? break;
>
> All that code in this case can go away.

Right!

>> +static void em_sti_register_clockevent(struct em_sti_priv *p)
>> +{
>> + ? ? struct clock_event_device *ced = &p->ced;
>> +
>> + ? ? memset(ced, 0, sizeof(*ced));
>> + ? ? ced->name = dev_name(&p->pdev->dev);
>> + ? ? ced->features = CLOCK_EVT_FEAT_PERIODIC;
>> + ? ? ced->features |= CLOCK_EVT_FEAT_ONESHOT;
>
> If you make that:
>
> ? ? ? ?ced->features = CLOCK_EVT_FEAT_ONESHOT;

Gotcha!

Thanks,

/ magnus

2012-05-25 09:39:27

by Magnus Damm

[permalink] [raw]
Subject: [tip:timers/core] clocksource: em_sti: Add DT support

Commit-ID: fc0830fe017d02b7b4995b5c402b484b65d9dfc6
Gitweb: http://git.kernel.org/tip/fc0830fe017d02b7b4995b5c402b484b65d9dfc6
Author: Magnus Damm <[email protected]>
AuthorDate: Wed, 9 May 2012 23:39:50 +0900
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 25 May 2012 11:32:06 +0200

clocksource: em_sti: Add DT support

Update the em-sti driver to support DT.

Signed-off-by: Magnus Damm <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/20120509143950.27521.7949.sendpatchset@w520
Signed-off-by: Thomas Gleixner <[email protected]>
---
drivers/clocksource/em_sti.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c
index 719584a..372051d 100644
--- a/drivers/clocksource/em_sti.c
+++ b/drivers/clocksource/em_sti.c
@@ -384,11 +384,18 @@ static int __devexit em_sti_remove(struct platform_device *pdev)
return -EBUSY; /* cannot unregister clockevent and clocksource */
}

+static const struct of_device_id em_sti_dt_ids[] __devinitconst = {
+ { .compatible = "renesas,em-sti", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
+
static struct platform_driver em_sti_device_driver = {
.probe = em_sti_probe,
.remove = __devexit_p(em_sti_remove),
.driver = {
.name = "em_sti",
+ .of_match_table = em_sti_dt_ids,
}
};