From: Nick Hawkins <[email protected]>
Add support for the HPE GXP SOC timer. The GXP supports several
different kinds of timers but for the purpose of this driver there
is only support for the General Timer. The timer has a 1us
resolution and is 32 bits.
Signed-off-by: Nick Hawkins <[email protected]>
---
drivers/clocksource/Kconfig | 8 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/gxp-timer.c | 159 ++++++++++++++++++++++++++++++++
3 files changed, 168 insertions(+)
create mode 100644 drivers/clocksource/gxp-timer.c
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index cfb8ea0df3b1..5916dade7608 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -617,6 +617,14 @@ config CLKSRC_ST_LPC
Enable this option to use the Low Power controller timer
as clocksource.
+config GXP_TIMER
+ bool "GXP timer driver"
+ depends on ARCH_HPE
+ default y
+ help
+ Provides a driver for the timer control found on HPE
+ GXP SOCs. This is required for all GXP SOCs.
+
config ATCPIT100_TIMER
bool "ATCPIT100 timer driver"
depends on NDS32 || COMPILE_TEST
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index fa5f624eadb6..dbfb8c56a8a0 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -89,3 +89,4 @@ obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o
+obj-$(CONFIG_GXP_TIMER) += gxp-timer.o
diff --git a/drivers/clocksource/gxp-timer.c b/drivers/clocksource/gxp-timer.c
new file mode 100644
index 000000000000..a24cd1cc5c04
--- /dev/null
+++ b/drivers/clocksource/gxp-timer.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P.*/
+
+#include <linux/bitops.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sched_clock.h>
+
+#include <asm/irq.h>
+
+#define TIMER0_FREQ 1000000
+
+/*TCS Stands for Timer Control/Status: these are masks to be used in*/
+/* the Timer Count Registers */
+#define MASK_TCS_ENABLE 0x01
+#define MASK_TCS_PERIOD 0x02
+#define MASK_TCS_RELOAD 0x04
+#define MASK_TCS_TC 0x80
+
+struct gxp_timer {
+ void __iomem *counter;
+ void __iomem *control;
+ struct clock_event_device evt;
+};
+
+static void __iomem *system_clock __read_mostly;
+
+static inline struct gxp_timer *to_gxp_timer(struct clock_event_device *evt_dev)
+{
+ return container_of(evt_dev, struct gxp_timer, evt);
+}
+
+static u64 notrace gxp_sched_read(void)
+{
+ return readl_relaxed(system_clock);
+}
+
+static int gxp_time_set_next_event(unsigned long event,
+ struct clock_event_device *evt_dev)
+{
+ struct gxp_timer *timer = to_gxp_timer(evt_dev);
+ /* Stop counting and disable interrupt before updating */
+ writeb_relaxed(MASK_TCS_TC, timer->control);
+ writel_relaxed(event, timer->counter);
+ writeb_relaxed(MASK_TCS_TC | MASK_TCS_ENABLE, timer->control);
+
+ return 0;
+}
+
+static irqreturn_t gxp_time_interrupt(int irq, void *dev_id)
+{
+ struct gxp_timer *timer = dev_id;
+ void (*event_handler)(struct clock_event_device *timer);
+
+ if (!(readb_relaxed(timer->control) & MASK_TCS_TC))
+ return IRQ_NONE;
+
+ writeb_relaxed(MASK_TCS_TC, timer->control);
+
+ event_handler = READ_ONCE(timer->evt.event_handler);
+ event_handler(&timer->evt);
+
+ return IRQ_HANDLED;
+}
+
+static int __init gxp_timer_init(struct device_node *node)
+{
+ void __iomem *base_counter;
+ void __iomem *base_control;
+ u32 freq;
+ int ret, irq;
+ struct gxp_timer *gxp_timer;
+
+ base_counter = of_iomap(node, 0);
+ if (!base_counter) {
+ pr_err("Can't remap counter registers");
+ ret = -ENXIO;
+ return ret;
+ }
+
+ base_control = of_iomap(node, 1);
+ if (!base_control) {
+ pr_err("Can't remap control registers");
+ ret = -ENXIO;
+ goto err_iounmap;
+ }
+
+ system_clock = of_iomap(node, 2);
+ if (!system_clock) {
+ pr_err("Can't remap control registers");
+ ret = -ENXIO;
+ goto err_iounmap;
+ }
+
+ if (of_property_read_u32(node, "clock-frequency", &freq)) {
+ pr_err("Can't read clock-frequency\n");
+ ret = -EIO;
+ goto err_iounmap;
+ }
+
+ sched_clock_register(gxp_sched_read, 32, freq);
+ clocksource_mmio_init(system_clock, node->name, freq,
+ 300, 32, clocksource_mmio_readl_up);
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ ret = -EINVAL;
+ pr_err("GXP Timer Can't parse IRQ %d", irq);
+ goto err_iounmap;
+ }
+
+ gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL);
+ if (!gxp_timer) {
+ ret = -ENOMEM;
+ goto err_iounmap;
+ }
+
+ gxp_timer->counter = base_counter;
+ gxp_timer->control = base_control;
+ gxp_timer->evt.name = node->name;
+ gxp_timer->evt.rating = 300;
+ gxp_timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
+ gxp_timer->evt.set_next_event = gxp_time_set_next_event;
+ gxp_timer->evt.cpumask = cpumask_of(0);
+
+ if (request_irq(irq, gxp_time_interrupt, IRQF_TIMER | IRQF_SHARED,
+ node->name, gxp_timer)) {
+ ret = -EIO;
+ pr_err("%s: request_irq() failed\n", "GXP Timer Tick");
+ goto err_timer_free;
+ }
+
+ clockevents_config_and_register(&gxp_timer->evt, TIMER0_FREQ,
+ 0xf, 0xffffffff);
+
+ pr_info("gxp: system timer (irq = %d)\n", irq);
+ return 0;
+
+
+err_timer_free:
+ kfree(gxp_timer);
+
+err_iounmap:
+ iounmap(system_clock);
+ iounmap(base_control);
+ iounmap(base_counter);
+ return ret;
+}
+
+TIMER_OF_DECLARE(gxp, "hpe,gxp-timer", gxp_timer_init);
--
2.17.1
On 10/03/2022 20:52, [email protected] wrote:
> From: Nick Hawkins <[email protected]>
>
> Add support for the HPE GXP SOC timer. The GXP supports several
> different kinds of timers but for the purpose of this driver there
> is only support for the General Timer. The timer has a 1us
> resolution and is 32 bits.
>
> Signed-off-by: Nick Hawkins <[email protected]>
> ---
> drivers/clocksource/Kconfig | 8 ++
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/gxp-timer.c | 159 ++++++++++++++++++++++++++++++++
> 3 files changed, 168 insertions(+)
> create mode 100644 drivers/clocksource/gxp-timer.c
Please for the sake of consistency, rename the timer to timer-qxp.c
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index cfb8ea0df3b1..5916dade7608 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -617,6 +617,14 @@ config CLKSRC_ST_LPC
> Enable this option to use the Low Power controller timer
> as clocksource.
>
> +config GXP_TIMER
> + bool "GXP timer driver"
> + depends on ARCH_HPE
> + default y
> + help
> + Provides a driver for the timer control found on HPE
> + GXP SOCs. This is required for all GXP SOCs.
Regarding the silent option:
https://www.spinics.net/lists/arm-kernel/msg936976.html
> config ATCPIT100_TIMER
> bool "ATCPIT100 timer driver"
> depends on NDS32 || COMPILE_TEST
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index fa5f624eadb6..dbfb8c56a8a0 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -89,3 +89,4 @@ obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
> obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
> obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
> obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o
> +obj-$(CONFIG_GXP_TIMER) += gxp-timer.o
> diff --git a/drivers/clocksource/gxp-timer.c b/drivers/clocksource/gxp-timer.c
> new file mode 100644
> index 000000000000..a24cd1cc5c04
> --- /dev/null
> +++ b/drivers/clocksource/gxp-timer.c
> @@ -0,0 +1,159 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P.*/
> +
> +#include <linux/bitops.h>
> +#include <linux/clockchips.h>
> +#include <linux/clocksource.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqreturn.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
This header is not needed.
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/sched_clock.h>
> +
> +#include <asm/irq.h>
This header is not needed AFAICT.
Please double check the headers above are all needed.
> +#define TIMER0_FREQ 1000000
> +
> +/*TCS Stands for Timer Control/Status: these are masks to be used in*/
> +/* the Timer Count Registers */
> +#define MASK_TCS_ENABLE 0x01
> +#define MASK_TCS_PERIOD 0x02
> +#define MASK_TCS_RELOAD 0x04
> +#define MASK_TCS_TC 0x80
> +
> +struct gxp_timer {
> + void __iomem *counter;
> + void __iomem *control;
> + struct clock_event_device evt;
> +};
> +
> +static void __iomem *system_clock __read_mostly;
> +
> +static inline struct gxp_timer *to_gxp_timer(struct clock_event_device *evt_dev)
> +{
> + return container_of(evt_dev, struct gxp_timer, evt);
> +}
> +
> +static u64 notrace gxp_sched_read(void)
> +{
> + return readl_relaxed(system_clock);
> +}
> +
> +static int gxp_time_set_next_event(unsigned long event,
> + struct clock_event_device *evt_dev)
> +{
> + struct gxp_timer *timer = to_gxp_timer(evt_dev);
nit: add a line to separate the declaration and the code below.
> + /* Stop counting and disable interrupt before updating */
> + writeb_relaxed(MASK_TCS_TC, timer->control);
> + writel_relaxed(event, timer->counter);
> + writeb_relaxed(MASK_TCS_TC | MASK_TCS_ENABLE, timer->control);
> +
> + return 0;
> +}
> +
> +static irqreturn_t gxp_time_interrupt(int irq, void *dev_id)
s/gxp_time/gxp_timer/
> +{
> + struct gxp_timer *timer = dev_id;
> + void (*event_handler)(struct clock_event_device *timer);
> +
> + if (!(readb_relaxed(timer->control) & MASK_TCS_TC))
> + return IRQ_NONE;
> +
> + writeb_relaxed(MASK_TCS_TC, timer->control);
> +
> + event_handler = READ_ONCE(timer->evt.event_handler);
> + event_handler(&timer->evt);
Why READ_ONCE ?
Do timer->evt.event_handler();
Or alternatively pass the request_irq() &timer->evt and use to_gxp_timer()
> + return IRQ_HANDLED;
> +}
> +
> +static int __init gxp_timer_init(struct device_node *node)
> +{
> + void __iomem *base_counter;
> + void __iomem *base_control;
> + u32 freq;
> + int ret, irq;
> + struct gxp_timer *gxp_timer;
> +
> + base_counter = of_iomap(node, 0);
> + if (!base_counter) {
> + pr_err("Can't remap counter registers");
> + ret = -ENXIO;
> + return ret;
return -ENXIO;
> + }
> +
> + base_control = of_iomap(node, 1);
> + if (!base_control) {
> + pr_err("Can't remap control registers");
> + ret = -ENXIO;
> + goto err_iounmap;
> + }
> +
> + system_clock = of_iomap(node, 2);
> + if (!system_clock) {
> + pr_err("Can't remap control registers");
> + ret = -ENXIO;
> + goto err_iounmap;
> + }
> +
> + if (of_property_read_u32(node, "clock-frequency", &freq)) {
> + pr_err("Can't read clock-frequency\n");
> + ret = -EIO;
> + goto err_iounmap;
> + }
> +
> + sched_clock_register(gxp_sched_read, 32, freq);
> + clocksource_mmio_init(system_clock, node->name, freq,
> + 300, 32, clocksource_mmio_readl_up);
> +
> + irq = irq_of_parse_and_map(node, 0);
> + if (irq <= 0) {
> + ret = -EINVAL;
> + pr_err("GXP Timer Can't parse IRQ %d", irq);
> + goto err_iounmap;
> + }
> +
> + gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL);
> + if (!gxp_timer) {
> + ret = -ENOMEM;
> + goto err_iounmap;
> + }
> +
> + gxp_timer->counter = base_counter;
> + gxp_timer->control = base_control;
> + gxp_timer->evt.name = node->name; > + gxp_timer->evt.rating = 300;
> + gxp_timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
> + gxp_timer->evt.set_next_event = gxp_time_set_next_event;
> + gxp_timer->evt.cpumask = cpumask_of(0);
> +
ret = request_irq();
> + if (request_irq(irq, gxp_time_interrupt, IRQF_TIMER | IRQF_SHARED,
> + node->name, gxp_timer)) {
> + ret = -EIO;
Remove above ret = -EIO;
> + pr_err("%s: request_irq() failed\n", "GXP Timer Tick");
> + goto err_timer_free;
> + }
> +
> + clockevents_config_and_register(&gxp_timer->evt, TIMER0_FREQ,
> + 0xf, 0xffffffff);
> +
> + pr_info("gxp: system timer (irq = %d)\n", irq);
s/pr_info/pr_debug/
> + return 0;
> +
> +
> +err_timer_free:
> + kfree(gxp_timer);
> +
> +err_iounmap:
> + iounmap(system_clock);
> + iounmap(base_control);
> + iounmap(base_counter);
> + return ret;
> +}
> +
> +TIMER_OF_DECLARE(gxp, "hpe,gxp-timer", gxp_timer_init);
--
<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
-----Original Message-----
From: Daniel Lezcano [mailto:[email protected]]
Sent: Wednesday, April 6, 2022 6:13 AM
To: Hawkins, Nick <[email protected]>; Verdun, Jean-Marie <[email protected]>
Cc: Thomas Gleixner <[email protected]>; [email protected]
Subject: Re: [PATCH v3 04/10] clocksource/drivers: Add HPE GXP timer
On 10/03/2022 20:52, [email protected] wrote:
> > From: Nick Hawkins <[email protected]> >
> >
> > Add support for the HPE GXP SOC timer. The GXP supports several
> > different kinds of timers but for the purpose of this driver there is
> > only support for the General Timer. The timer has a 1us resolution and
> > is 32 bits.
> >
> > Signed-off-by: Nick Hawkins <[email protected]> >
> > ---
> > drivers/clocksource/Kconfig | 8 ++
> > drivers/clocksource/Makefile | 1 +
> > drivers/clocksource/gxp-timer.c | 159 ++++++++++++++++++++++++++++++++
> > 3 files changed, 168 insertions(+)
> > create mode 100644 drivers/clocksource/gxp-timer.c
> Please for the sake of consistency, rename the timer to timer-qxp.c
Fixed.
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index cfb8ea0df3b1..5916dade7608 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -617,6 +617,14 @@ config CLKSRC_ST_LPC
> > Enable this option to use the Low Power controller timer
> > as clocksource.
> >
> > +config GXP_TIMER
> > + bool "GXP timer driver"
> > + depends on ARCH_HPE
> > + default y
> > + help
> > + Provides a driver for the timer control found on HPE
> > + GXP SOCs. This is required for all GXP SOCs.
> Regarding the silent option:
> https://www.spinics.net/lists/arm-kernel/msg936976.html
What I have understood from that is we need ---> bool "GXP timer driver" if COMPILE_TEST
This is the modification I have made.
One a side note: The next submission will have several implementation differences due to requirements from the dtsi review.
1) The timer will get its frequency from the ppuclk
2) The timer will spawn a watchdog timer child and pass the base register to it. See: https://lore.kernel.org/all/CAK8P3a3jr-FkyxLff2cK4=X-4AShnKkeYMRKsvUg=2W0bTviiQ@mail.gmail.com/
> > config ATCPIT100_TIMER
> > bool "ATCPIT100 timer driver"
> > depends on NDS32 || COMPILE_TEST
> > diff --git a/drivers/clocksource/Makefile
> > b/drivers/clocksource/Makefile index fa5f624eadb6..dbfb8c56a8a0 100644
> > --- a/drivers/clocksource/Makefile
> > +++ b/drivers/clocksource/Makefile
> > @@ -89,3 +89,4 @@ obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
> > obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
> > obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
> > obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o
> > +obj-$(CONFIG_GXP_TIMER) += gxp-timer.o
> > diff --git a/drivers/clocksource/gxp-timer.c
> > b/drivers/clocksource/gxp-timer.c new file mode 100644 index
> > 000000000000..a24cd1cc5c04
> > --- /dev/null
> > +++ b/drivers/clocksource/gxp-timer.c
> > @@ -0,0 +1,159 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company,
> > +L.P.*/
> > +
> > +#include <linux/bitops.h> >
> > +#include <linux/clockchips.h> >
> > +#include <linux/clocksource.h> >
> > +#include <linux/interrupt.h> >
> > +#include <linux/irqreturn.h> >
> > +#include <linux/kernel.h> >
> > +#include <linux/module.h> >
> This header is not needed.
> > +#include <linux/of_address.h> >
> > +#include <linux/of_irq.h> >
> > +#include <linux/of_platform.h> >
> > +#include <linux/slab.h> >
> > +#include <linux/string.h> >
> > +#include <linux/sched_clock.h> >
> > +
> > +#include <asm/irq.h> >
> This header is not needed AFAICT.
> Please double check the headers above are all needed.
Done ended up removing irq, string, slab, bitops, irqreturn
> > +#define TIMER0_FREQ 1000000
> > +
> > +/*TCS Stands for Timer Control/Status: these are masks to be used
> > +in*/
> > +/* the Timer Count Registers */
> > +#define MASK_TCS_ENABLE 0x01
> > +#define MASK_TCS_PERIOD 0x02
> > +#define MASK_TCS_RELOAD 0x04
> > +#define MASK_TCS_TC 0x80
> > +
> > +struct gxp_timer {
> > + void __iomem *counter;
> > + void __iomem *control;
> > + struct clock_event_device evt;
> > +};
> > +
> > +static void __iomem *system_clock __read_mostly;
> > +
> > +static inline struct gxp_timer *to_gxp_timer(struct
> > +clock_event_device *evt_dev) {
> > + return container_of(evt_dev, struct gxp_timer, evt); }
> > +
> > +static u64 notrace gxp_sched_read(void) {
> > + return readl_relaxed(system_clock);
> > +}
> > +
> > +static int gxp_time_set_next_event(unsigned long event,
> > + struct clock_event_device *evt_dev) {
> > + struct gxp_timer *timer = to_gxp_timer(evt_dev);
> nit: add a line to separate the declaration and the code below.
Done
> > + /* Stop counting and disable interrupt before updating */
> > + writeb_relaxed(MASK_TCS_TC, timer-> >control);
> > + writel_relaxed(event, timer-> >counter);
> > + writeb_relaxed(MASK_TCS_TC | MASK_TCS_ENABLE, timer-> >control);
> > +
> > + return 0;
> > +}
> > +
> > +static irqreturn_t gxp_time_interrupt(int irq, void *dev_id)
> s/gxp_time/gxp_timer/
Done
> > +{
> > + struct gxp_timer *timer = dev_id;
> > + void (*event_handler)(struct clock_event_device *timer);
> > +
> > + if (!(readb_relaxed(timer-> >control) & MASK_TCS_TC))
> > + return IRQ_NONE;
> > +
> > + writeb_relaxed(MASK_TCS_TC, timer-> >control);
> > +
> > + event_handler = READ_ONCE(timer-> >evt.event_handler);
> > + event_handler(&timer-> >evt);
> Why READ_ONCE ?
> Do timer-> >evt.event_handler();
> Or alternatively pass the request_irq() &timer-> >evt and use to_gxp_timer()
Fixed
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int __init gxp_timer_init(struct device_node *node) {
> > + void __iomem *base_counter;
> > + void __iomem *base_control;
> > + u32 freq;
> > + int ret, irq;
> > + struct gxp_timer *gxp_timer;
> > +
> > + base_counter = of_iomap(node, 0);
> > + if (!base_counter) {
> > + pr_err("Can't remap counter registers");
> > + ret = -ENXIO;
> > + return ret;
> return -ENXIO;
Done
> > + }
> > +
> > + base_control = of_iomap(node, 1);
> > + if (!base_control) {
> > + pr_err("Can't remap control registers");
> > + ret = -ENXIO;
> > + goto err_iounmap;
> > + }
> > +
> > + system_clock = of_iomap(node, 2);
> > + if (!system_clock) {
> > + pr_err("Can't remap control registers");
> > + ret = -ENXIO;
> > + goto err_iounmap;
> > + }
> > +
> > + if (of_property_read_u32(node, "clock-frequency", &freq)) {
> > + pr_err("Can't read clock-frequency\n");
> > + ret = -EIO;
> > + goto err_iounmap;
> > + }
> > +
> > + sched_clock_register(gxp_sched_read, 32, freq);
> > + clocksource_mmio_init(system_clock, node-> >name, freq,
> > + 300, 32, clocksource_mmio_readl_up);
> > +
> > + irq = irq_of_parse_and_map(node, 0);
> > + if (irq <= 0) {
> > + ret = -EINVAL;
> > + pr_err("GXP Timer Can't parse IRQ %d", irq);
> > + goto err_iounmap;
> > + }
> > +
> > + gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL);
> > + if (!gxp_timer) {
> > + ret = -ENOMEM;
> > + goto err_iounmap;
> > + }
> > +
> > + gxp_timer-> >counter = base_counter;
> > + gxp_timer-> >control = base_control;
> > + gxp_timer-> >evt.name = node-> >name; > > + gxp_timer-> >evt.rating = 300;
> > + gxp_timer-> >evt.features = CLOCK_EVT_FEAT_ONESHOT;
> > + gxp_timer-> >evt.set_next_event = gxp_time_set_next_event;
> > + gxp_timer-> >evt.cpumask = cpumask_of(0);
> > +
> ret = request_irq();
Done
> > + if (request_irq(irq, gxp_time_interrupt, IRQF_TIMER | IRQF_SHARED,
> > + node-> >name, gxp_timer)) {
> > + ret = -EIO;
> Remove above ret = -EIO;
Done
> > + pr_err("%s: request_irq() failed\n", "GXP Timer Tick");
> > + goto err_timer_free;
> > + }
> > +
> > + clockevents_config_and_register(&gxp_timer-> >evt, TIMER0_FREQ,
> > + 0xf, 0xffffffff);
> > +
> > + pr_info("gxp: system timer (irq = %d)\n", irq);
> s/pr_info/pr_debug/
Done
> > + return 0;
> > +
> > +
> > +err_timer_free:
> > + kfree(gxp_timer);
> > +
> > +err_iounmap:
> > + iounmap(system_clock);
> > + iounmap(base_control);
> > + iounmap(base_counter);
> > + return ret;
> > +}
> > +
> > +TIMER_OF_DECLARE(gxp, "hpe,gxp-timer", gxp_timer_init);
Thanks,
-Nick Hawkins