Commit fef92cd2 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'timers-v5.11' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clocksource/event driver updates from Daniel Lezcano:

 - Add static annotation for the sp804 init functions (Zhen Lei)

 - Code cleanups and error code path at init time fixes on the sp804
   (Kefen Wang)

 - Add new OST timer driver device tree bindings (Zhou Yanjie)

 - Remove EZChip NPS clocksource driver corresponding to the NPS
   platform which was removed from the ARC architecture (Vineet Gupta)

 - Add missing clk_disable_unprepare() on error path for Orion (Yang
   Yingliang)

 - Add device tree bindings documentation for Renesas r8a774e1
   (Marian-Cristian Rotariu)

 - Convert Renesas TMU to json-schema (Geert Uytterhoeven)

 - Fix memory leak on the error path at init time on the cadence_ttc
   driver (Yu Kuai)

 - Fix section mismatch for Ingenic timer driver (Daniel Lezcano)

 - Make RISCV_TIMER depends on RISCV_SBI (Kefeng Wang)

Link: https://lore.kernel.org/r/028084fa-d29b-a1d5-7eab-17f77ef69863@linaro.org
parents b9965449 ab310544
* Renesas R-Mobile/R-Car Timer Unit (TMU)
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
Required Properties:
- compatible: must contain one or more of the following:
- "renesas,tmu-r8a7740" for the r8a7740 TMU
- "renesas,tmu-r8a774a1" for the r8a774A1 TMU
- "renesas,tmu-r8a774b1" for the r8a774B1 TMU
- "renesas,tmu-r8a774c0" for the r8a774C0 TMU
- "renesas,tmu-r8a7778" for the r8a7778 TMU
- "renesas,tmu-r8a7779" for the r8a7779 TMU
- "renesas,tmu-r8a77970" for the r8a77970 TMU
- "renesas,tmu-r8a77980" for the r8a77980 TMU
- "renesas,tmu" for any TMU.
This is a fallback for the above renesas,tmu-* entries
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Optional Properties:
- #renesas,channels: number of channels implemented by the timer, must be 2
or 3 (if not specified the value defaults to 3).
Example: R8A7779 (R-Car H1) TMU0 node
tmu0: timer@ffd80000 {
compatible = "renesas,tmu-r8a7779", "renesas,tmu";
reg = <0xffd80000 0x30>;
interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>,
<0 33 IRQ_TYPE_LEVEL_HIGH>,
<0 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
#renesas,channels = <3>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/renesas,tmu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Mobile/R-Car Timer Unit (TMU)
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
description:
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
properties:
compatible:
items:
- enum:
- renesas,tmu-r8a7740 # R-Mobile A1
- renesas,tmu-r8a774a1 # RZ/G2M
- renesas,tmu-r8a774b1 # RZ/G2N
- renesas,tmu-r8a774c0 # RZ/G2E
- renesas,tmu-r8a774e1 # RZ/G2H
- renesas,tmu-r8a7778 # R-Car M1A
- renesas,tmu-r8a7779 # R-Car H1
- renesas,tmu-r8a77970 # R-Car V3M
- renesas,tmu-r8a77980 # R-Car V3H
- const: renesas,tmu
reg:
maxItems: 1
interrupts:
minItems: 2
maxItems: 3
clocks:
maxItems: 1
clock-names:
const: fck
power-domains:
maxItems: 1
resets:
maxItems: 1
'#renesas,channels':
description:
Number of channels implemented by the timer.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 2, 3 ]
default: 3
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
if:
not:
properties:
compatible:
contains:
enum:
- renesas,tmu-r8a7740
- renesas,tmu-r8a7778
- renesas,tmu-r8a7779
then:
required:
- resets
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7779-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7779-sysc.h>
tmu0: timer@ffd80000 {
compatible = "renesas,tmu-r8a7779", "renesas,tmu";
reg = <0xffd80000 0x30>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
#renesas,channels = <3>;
};
...@@ -275,16 +275,6 @@ config CLKSRC_TI_32K ...@@ -275,16 +275,6 @@ config CLKSRC_TI_32K
This option enables support for Texas Instruments 32.768 Hz clocksource This option enables support for Texas Instruments 32.768 Hz clocksource
available on many OMAP-like platforms. available on many OMAP-like platforms.
config CLKSRC_NPS
bool "NPS400 clocksource driver" if COMPILE_TEST
depends on !PHYS_ADDR_T_64BIT
select CLKSRC_MMIO
select TIMER_OF if OF
help
NPS400 clocksource support.
It has a 64-bit counter with update rate up to 1000MHz.
This counter is accessed via couple of 32-bit memory-mapped registers.
config CLKSRC_STM32 config CLKSRC_STM32
bool "Clocksource for STM32 SoCs" if !ARCH_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32
depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
...@@ -654,7 +644,7 @@ config ATCPIT100_TIMER ...@@ -654,7 +644,7 @@ config ATCPIT100_TIMER
config RISCV_TIMER config RISCV_TIMER
bool "Timer for the RISC-V platform" if COMPILE_TEST bool "Timer for the RISC-V platform" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK && RISCV depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI
select TIMER_PROBE select TIMER_PROBE
select TIMER_OF select TIMER_OF
help help
......
...@@ -56,7 +56,6 @@ obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o ...@@ -56,7 +56,6 @@ obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o
obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o
obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o
obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += timer-owl.o obj-$(CONFIG_OWL_TIMER) += timer-owl.o
obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o
......
...@@ -127,7 +127,7 @@ static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id) ...@@ -127,7 +127,7 @@ static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct clk * __init ingenic_tcu_get_clock(struct device_node *np, int id) static struct clk *ingenic_tcu_get_clock(struct device_node *np, int id)
{ {
struct of_phandle_args args; struct of_phandle_args args;
......
...@@ -413,10 +413,8 @@ static int __init ttc_setup_clockevent(struct clk *clk, ...@@ -413,10 +413,8 @@ static int __init ttc_setup_clockevent(struct clk *clk,
ttcce->ttc.clk = clk; ttcce->ttc.clk = clk;
err = clk_prepare_enable(ttcce->ttc.clk); err = clk_prepare_enable(ttcce->ttc.clk);
if (err) { if (err)
kfree(ttcce); goto out_kfree;
return err;
}
ttcce->ttc.clk_rate_change_nb.notifier_call = ttcce->ttc.clk_rate_change_nb.notifier_call =
ttc_rate_change_clockevent_cb; ttc_rate_change_clockevent_cb;
...@@ -426,7 +424,7 @@ static int __init ttc_setup_clockevent(struct clk *clk, ...@@ -426,7 +424,7 @@ static int __init ttc_setup_clockevent(struct clk *clk,
&ttcce->ttc.clk_rate_change_nb); &ttcce->ttc.clk_rate_change_nb);
if (err) { if (err) {
pr_warn("Unable to register clock notifier.\n"); pr_warn("Unable to register clock notifier.\n");
return err; goto out_kfree;
} }
ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk); ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk);
...@@ -455,15 +453,17 @@ static int __init ttc_setup_clockevent(struct clk *clk, ...@@ -455,15 +453,17 @@ static int __init ttc_setup_clockevent(struct clk *clk,
err = request_irq(irq, ttc_clock_event_interrupt, err = request_irq(irq, ttc_clock_event_interrupt,
IRQF_TIMER, ttcce->ce.name, ttcce); IRQF_TIMER, ttcce->ce.name, ttcce);
if (err) { if (err)
kfree(ttcce); goto out_kfree;
return err;
}
clockevents_config_and_register(&ttcce->ce, clockevents_config_and_register(&ttcce->ce,
ttcce->ttc.freq / PRESCALE, 1, 0xfffe); ttcce->ttc.freq / PRESCALE, 1, 0xfffe);
return 0; return 0;
out_kfree:
kfree(ttcce);
return err;
} }
static int __init ttc_timer_probe(struct platform_device *pdev) static int __init ttc_timer_probe(struct platform_device *pdev)
......
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/cpu.h>
#include <soc/nps/common.h>
#define NPS_MSU_TICK_LOW 0xC8
#define NPS_CLUSTER_OFFSET 8
#define NPS_CLUSTER_NUM 16
/* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */
static void *nps_msu_reg_low_addr[NPS_CLUSTER_NUM] __read_mostly;
static int __init nps_get_timer_clk(struct device_node *node,
unsigned long *timer_freq,
struct clk **clk)
{
int ret;
*clk = of_clk_get(node, 0);
ret = PTR_ERR_OR_ZERO(*clk);
if (ret) {
pr_err("timer missing clk\n");
return ret;
}
ret = clk_prepare_enable(*clk);
if (ret) {
pr_err("Couldn't enable parent clk\n");
clk_put(*clk);
return ret;
}
*timer_freq = clk_get_rate(*clk);
if (!(*timer_freq)) {
pr_err("Couldn't get clk rate\n");
clk_disable_unprepare(*clk);
clk_put(*clk);
return -EINVAL;
}
return 0;
}
static u64 nps_clksrc_read(struct clocksource *clksrc)
{
int cluster = raw_smp_processor_id() >> NPS_CLUSTER_OFFSET;
return (u64)ioread32be(nps_msu_reg_low_addr[cluster]);
}
static int __init nps_setup_clocksource(struct device_node *node)
{
int ret, cluster;
struct clk *clk;
unsigned long nps_timer1_freq;
for (cluster = 0; cluster < NPS_CLUSTER_NUM; cluster++)
nps_msu_reg_low_addr[cluster] =
nps_host_reg((cluster << NPS_CLUSTER_OFFSET),
NPS_MSU_BLKID, NPS_MSU_TICK_LOW);
ret = nps_get_timer_clk(node, &nps_timer1_freq, &clk);
if (ret)
return ret;
ret = clocksource_mmio_init(nps_msu_reg_low_addr, "nps-tick",
nps_timer1_freq, 300, 32, nps_clksrc_read);
if (ret) {
pr_err("Couldn't register clock source.\n");
clk_disable_unprepare(clk);
}
return ret;
}
TIMER_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer",
nps_setup_clocksource);
TIMER_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1",
nps_setup_clocksource);
#ifdef CONFIG_EZNPS_MTM_EXT
#include <soc/nps/mtm.h>
/* Timer related Aux registers */
#define NPS_REG_TIMER0_TSI 0xFFFFF850
#define NPS_REG_TIMER0_LIMIT 0x23
#define NPS_REG_TIMER0_CTRL 0x22
#define NPS_REG_TIMER0_CNT 0x21
/*
* Interrupt Enabled (IE) - re-arm the timer
* Not Halted (NH) - is cleared when working with JTAG (for debug)
*/
#define TIMER0_CTRL_IE BIT(0)
#define TIMER0_CTRL_NH BIT(1)
static unsigned long nps_timer0_freq;
static unsigned long nps_timer0_irq;
static void nps_clkevent_rm_thread(void)
{
int thread;
unsigned int cflags, enabled_threads;
hw_schd_save(&cflags);
enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI);
/* remove thread from TSI1 */
thread = read_aux_reg(CTOP_AUX_THREAD_ID);
enabled_threads &= ~(1 << thread);
write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads);
/* Acknowledge and if needed re-arm the timer */
if (!enabled_threads)
write_aux_reg(NPS_REG_TIMER0_CTRL, TIMER0_CTRL_NH);
else
write_aux_reg(NPS_REG_TIMER0_CTRL,
TIMER0_CTRL_IE | TIMER0_CTRL_NH);
hw_schd_restore(cflags);
}
static void nps_clkevent_add_thread(unsigned long delta)
{
int thread;
unsigned int cflags, enabled_threads;
hw_schd_save(&cflags);
/* add thread to TSI1 */
thread = read_aux_reg(CTOP_AUX_THREAD_ID);
enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI);
enabled_threads |= (1 << thread);
write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads);
/* set next timer event */
write_aux_reg(NPS_REG_TIMER0_LIMIT, delta);
write_aux_reg(NPS_REG_TIMER0_CNT, 0);
write_aux_reg(NPS_REG_TIMER0_CTRL,
TIMER0_CTRL_IE | TIMER0_CTRL_NH);
hw_schd_restore(cflags);
}
/*
* Whenever anyone tries to change modes, we just mask interrupts
* and wait for the next event to get set.
*/
static int nps_clkevent_set_state(struct clock_event_device *dev)
{
nps_clkevent_rm_thread();
disable_percpu_irq(nps_timer0_irq);
return 0;
}
static int nps_clkevent_set_next_event(unsigned long delta,
struct clock_event_device *dev)
{
nps_clkevent_add_thread(delta);
enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE);
return 0;
}
static DEFINE_PER_CPU(struct clock_event_device, nps_clockevent_device) = {
.name = "NPS Timer0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 300,
.set_next_event = nps_clkevent_set_next_event,
.set_state_oneshot = nps_clkevent_set_state,
.set_state_oneshot_stopped = nps_clkevent_set_state,
.set_state_shutdown = nps_clkevent_set_state,
.tick_resume = nps_clkevent_set_state,
};
static irqreturn_t timer_irq_handler(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
nps_clkevent_rm_thread();
evt->event_handler(evt);
return IRQ_HANDLED;
}
static int nps_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *evt = this_cpu_ptr(&nps_clockevent_device);
evt->cpumask = cpumask_of(smp_processor_id());
clockevents_config_and_register(evt, nps_timer0_freq, 0, ULONG_MAX);
enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE);
return 0;
}
static int nps_timer_dying_cpu(unsigned int cpu)
{
disable_percpu_irq(nps_timer0_irq);
return 0;
}
static int __init nps_setup_clockevent(struct device_node *node)
{
struct clk *clk;
int ret;
nps_timer0_irq = irq_of_parse_and_map(node, 0);
if (nps_timer0_irq <= 0) {
pr_err("clockevent: missing irq\n");
return -EINVAL;
}
ret = nps_get_timer_clk(node, &nps_timer0_freq, &clk);
if (ret)
return ret;
/* Needs apriori irq_set_percpu_devid() done in intc map function */
ret = request_percpu_irq(nps_timer0_irq, timer_irq_handler,
"Timer0 (per-cpu-tick)",
&nps_clockevent_device);
if (ret) {
pr_err("Couldn't request irq\n");
clk_disable_unprepare(clk);
return ret;
}
ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING,
"clockevents/nps:starting",
nps_timer_starting_cpu,
nps_timer_dying_cpu);
if (ret) {
pr_err("Failed to setup hotplug state\n");
clk_disable_unprepare(clk);
free_percpu_irq(nps_timer0_irq, &nps_clockevent_device);
return ret;
}
return 0;
}
TIMER_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0",
nps_setup_clockevent);
#endif /* CONFIG_EZNPS_MTM_EXT */
...@@ -143,7 +143,8 @@ static int __init orion_timer_init(struct device_node *np) ...@@ -143,7 +143,8 @@ static int __init orion_timer_init(struct device_node *np)
irq = irq_of_parse_and_map(np, 1); irq = irq_of_parse_and_map(np, 1);
if (irq <= 0) { if (irq <= 0) {
pr_err("%pOFn: unable to parse timer1 irq\n", np); pr_err("%pOFn: unable to parse timer1 irq\n", np);
return -EINVAL; ret = -EINVAL;
goto out_unprep_clk;
} }
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
...@@ -160,7 +161,7 @@ static int __init orion_timer_init(struct device_node *np) ...@@ -160,7 +161,7 @@ static int __init orion_timer_init(struct device_node *np)
clocksource_mmio_readl_down); clocksource_mmio_readl_down);
if (ret) { if (ret) {
pr_err("Failed to initialize mmio timer\n"); pr_err("Failed to initialize mmio timer\n");
return ret; goto out_unprep_clk;
} }
sched_clock_register(orion_read_sched_clock, 32, rate); sched_clock_register(orion_read_sched_clock, 32, rate);
...@@ -170,7 +171,7 @@ static int __init orion_timer_init(struct device_node *np) ...@@ -170,7 +171,7 @@ static int __init orion_timer_init(struct device_node *np)
"orion_event", NULL); "orion_event", NULL);
if (ret) { if (ret) {
pr_err("%pOFn: unable to setup irq\n", np); pr_err("%pOFn: unable to setup irq\n", np);
return ret; goto out_unprep_clk;
} }
ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ; ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
...@@ -183,5 +184,9 @@ static int __init orion_timer_init(struct device_node *np) ...@@ -183,5 +184,9 @@ static int __init orion_timer_init(struct device_node *np)
orion_delay_timer_init(rate); orion_delay_timer_init(rate);
return 0; return 0;
out_unprep_clk:
clk_disable_unprepare(clk);
return ret;
} }
TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* Copyright (C) 1999 - 2003 ARM Limited * Copyright (C) 1999 - 2003 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd * Copyright (C) 2000 Deep Blue Solutions Ltd
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
...@@ -34,8 +37,7 @@ ...@@ -34,8 +37,7 @@
#define HISI_TIMER_BGLOAD 0x20 #define HISI_TIMER_BGLOAD 0x20
#define HISI_TIMER_BGLOAD_H 0x24 #define HISI_TIMER_BGLOAD_H 0x24
static struct sp804_timer arm_sp804_timer __initdata = {
struct sp804_timer __initdata arm_sp804_timer = {
.load = TIMER_LOAD, .load = TIMER_LOAD,
.value = TIMER_VALUE, .value = TIMER_VALUE,
.ctrl = TIMER_CTRL, .ctrl = TIMER_CTRL,
...@@ -44,7 +46,7 @@ struct sp804_timer __initdata arm_sp804_timer = { ...@@ -44,7 +46,7 @@ struct sp804_timer __initdata arm_sp804_timer = {
.width = 32, .width = 32,
}; };
struct sp804_timer __initdata hisi_sp804_timer = { static struct sp804_timer hisi_sp804_timer __initdata = {
.load = HISI_TIMER_LOAD, .load = HISI_TIMER_LOAD,
.load_h = HISI_TIMER_LOAD_H, .load_h = HISI_TIMER_LOAD_H,
.value = HISI_TIMER_VALUE, .value = HISI_TIMER_VALUE,
...@@ -59,40 +61,23 @@ static struct sp804_clkevt sp804_clkevt[NR_TIMERS]; ...@@ -59,40 +61,23 @@ static struct sp804_clkevt sp804_clkevt[NR_TIMERS];
static long __init sp804_get_clock_rate(struct clk *clk, const char *name) static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
{ {
long rate;
int err; int err;
if (!clk) if (!clk)
clk = clk_get_sys("sp804", name); clk = clk_get_sys("sp804", name);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
pr_err("sp804: %s clock not found: %ld\n", name, PTR_ERR(clk)); pr_err("%s clock not found: %ld\n", name, PTR_ERR(clk));
return PTR_ERR(clk); return PTR_ERR(clk);
} }
err = clk_prepare(clk); err = clk_prepare_enable(clk);
if (err) {
pr_err("sp804: clock failed to prepare: %d\n", err);
clk_put(clk);
return err;
}
err = clk_enable(clk);
if (err) { if (err) {
pr_err("sp804: clock failed to enable: %d\n", err); pr_err("clock failed to enable: %d\n", err);
clk_unprepare(clk);
clk_put(clk); clk_put(clk);
return err; return err;
} }
rate = clk_get_rate(clk); return clk_get_rate(clk);
if (rate < 0) {
pr_err("sp804: clock failed to get rate: %ld\n", rate);
clk_disable(clk);
clk_unprepare(clk);
clk_put(clk);
}
return rate;
} }
static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base) static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base)
...@@ -117,7 +102,7 @@ static u64 notrace sp804_read(void) ...@@ -117,7 +102,7 @@ static u64 notrace sp804_read(void)
return ~readl_relaxed(sched_clkevt->value); return ~readl_relaxed(sched_clkevt->value);
} }
int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name, const char *name,
struct clk *clk, struct clk *clk,
int use_sched_clock) int use_sched_clock)
...@@ -216,7 +201,7 @@ static struct clock_event_device sp804_clockevent = { ...@@ -216,7 +201,7 @@ static struct clock_event_device sp804_clockevent = {
.rating = 300, .rating = 300,
}; };
int __init sp804_clockevents_init(void __iomem *base, unsigned int irq, static int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
struct clk *clk, const char *name) struct clk *clk, const char *name)
{ {
struct clock_event_device *evt = &sp804_clockevent; struct clock_event_device *evt = &sp804_clockevent;
...@@ -236,7 +221,7 @@ int __init sp804_clockevents_init(void __iomem *base, unsigned int irq, ...@@ -236,7 +221,7 @@ int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
"timer", &sp804_clockevent)) "timer", &sp804_clockevent))
pr_err("%s: request_irq() failed\n", "timer"); pr_err("request_irq() failed\n");
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
return 0; return 0;
...@@ -298,7 +283,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time ...@@ -298,7 +283,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
if (of_clk_get_parent_count(np) == 3) { if (of_clk_get_parent_count(np) == 3) {
clk2 = of_clk_get(np, 1); clk2 = of_clk_get(np, 1);
if (IS_ERR(clk2)) { if (IS_ERR(clk2)) {
pr_err("sp804: %pOFn clock not found: %d\n", np, pr_err("%pOFn clock not found: %d\n", np,
(int)PTR_ERR(clk2)); (int)PTR_ERR(clk2));
clk2 = NULL; clk2 = NULL;
} }
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* /*
* This header provides clock numbers for the ingenic,tcu DT binding. * This header provides clock numbers for the Ingenic OST DT binding.
*/ */
#ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__ #ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define __DT_BINDINGS_CLOCK_INGENIC_OST_H__ #define __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define OST_CLK_PERCPU_TIMER 0 #define OST_CLK_PERCPU_TIMER 1
#define OST_CLK_GLOBAL_TIMER 1 #define OST_CLK_GLOBAL_TIMER 0
#define OST_CLK_PERCPU_TIMER0 1
#define OST_CLK_PERCPU_TIMER1 2
#define OST_CLK_PERCPU_TIMER2 3
#define OST_CLK_PERCPU_TIMER3 4
#endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */ #endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment