mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
- Fix DT bindings typos, readability and wrong information about
underflow and overflow interrupts for the RZ/G2L MTU3a driver (Biju
Das)
- Fix a memory leak in the error path when probing the i.MX GPT timer
(Jacky Bai)
- Don't use clk_get_rate() in atomic context as the function might
sleep. Store the clock and use notifiers to receive a clocke rate
change notification (Ivaylo Dimitrov)
- Remove superfluous error message when platform_get_irq() fails
because the underlying function already prints one (Yang Li)
- Add wakeup capability flag for the risc-V ACPI timer (Sunil V L)
- Fix initialization of the TCB timers which are in cascade as the
second timer is reset after the first wraps up leading to
inconsistent scheduler behavior (Ronald Wahl)
- Add DT bindings and driver for Cirrus Logic EP93xx (Nikita Shubin)
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmU5LMQACgkQqDIjiipP
6E+R2Af/e+3ViG7JPGxlFk1ihvSPrEpsMG5ypLBaUgaoagzjCCJf9fEwWqS1Wgm/
dAkI+cvQFKLdWpn7bWbXEgenCL+zdm+aTUL/2TS6gGV6452JzR+zWQj5yZ1RsY1+
pM8/+SiC1ynES9RhHM9ihbsvEiznXDfVM3rp2eG4N6RK29Rhs6rUav+rH5CAuVIf
wQhVd28gK5XywIjCe4k5bLGxG+uFxAjIFzPRaa99Xhy06Mhh0NagOZXfKGhjquGd
ZFCOHyLA3gS2yhAwMXsL2mT35Kc6YHyWdjtTT3GU/XNJQOgwU8k9zSmnND8IhHsd
DeAx3qmzU4PipsQdN+rTlYLh5PPOIQ==
=c30J
-----END PGP SIGNATURE-----
Merge tag 'timers-v6.7-rc1' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core
Pull timer driver updates from Daniel Lezcano:
- Fix DT bindings typos, readability and wrong information about
underflow and overflow interrupts for the RZ/G2L MTU3a driver (Biju
Das)
- Fix a memory leak in the error path when probing the i.MX GPT timer
(Jacky Bai)
- Don't use clk_get_rate() in atomic context as the function might
sleep. Store the clock and use notifiers to receive a clocke rate
change notification (Ivaylo Dimitrov)
- Remove superfluous error message when platform_get_irq() fails
because the underlying function already prints one (Yang Li)
- Add wakeup capability flag for the risc-V ACPI timer (Sunil V L)
- Fix initialization of the TCB timers which are in cascade as the
second timer is reset after the first wraps up leading to
inconsistent scheduler behavior (Ronald Wahl)
- Add DT bindings and driver for Cirrus Logic EP93xx (Nikita Shubin)
This commit is contained in:
commit
f4febfdbb4
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/timer/cirrus,ep9301-timer.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic EP93xx timer
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-timer
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-timer
|
||||
- cirrus,ep9307-timer
|
||||
- cirrus,ep9312-timer
|
||||
- cirrus,ep9315-timer
|
||||
- const: cirrus,ep9301-timer
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
timer@80810000 {
|
||||
compatible = "cirrus,ep9301-timer";
|
||||
reg = <0x80810000 0x100>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <19>;
|
||||
};
|
||||
...
|
||||
|
|
@ -11,8 +11,8 @@ maintainers:
|
|||
|
||||
description: |
|
||||
This hardware block consists of eight 16-bit timer channels and one
|
||||
32- bit timer channel. It supports the following specifications:
|
||||
- Pulse input/output: 28 lines max.
|
||||
32-bit timer channel. It supports the following specifications:
|
||||
- Pulse input/output: 28 lines max
|
||||
- Pulse input 3 lines
|
||||
- Count clock 11 clocks for each channel (14 clocks for MTU0, 12 clocks
|
||||
for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2 combination
|
||||
|
|
@ -23,11 +23,11 @@ description: |
|
|||
- Input capture function (noise filter setting available)
|
||||
- Counter-clearing operation
|
||||
- Simultaneous writing to multiple timer counters (TCNT)
|
||||
(excluding MTU8).
|
||||
(excluding MTU8)
|
||||
- Simultaneous clearing on compare match or input capture
|
||||
(excluding MTU8).
|
||||
(excluding MTU8)
|
||||
- Simultaneous input and output to registers in synchronization with
|
||||
counter operations (excluding MTU8).
|
||||
counter operations (excluding MTU8)
|
||||
- Up to 12-phase PWM output in combination with synchronous operation
|
||||
(excluding MTU8)
|
||||
- [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
|
||||
|
|
@ -40,26 +40,26 @@ description: |
|
|||
- [MTU3, MTU4, MTU6, and MTU7]
|
||||
- Through interlocked operation of MTU3/4 and MTU6/7, the positive and
|
||||
negative signals in six phases (12 phases in total) can be output in
|
||||
complementary PWM and reset-synchronized PWM operation.
|
||||
complementary PWM and reset-synchronized PWM operation
|
||||
- In complementary PWM mode, values can be transferred from buffer
|
||||
registers to temporary registers at crests and troughs of the timer-
|
||||
counter values or when the buffer registers (TGRD registers in MTU4
|
||||
and MTU7) are written to.
|
||||
- Double-buffering selectable in complementary PWM mode.
|
||||
and MTU7) are written to
|
||||
- Double-buffering selectable in complementary PWM mode
|
||||
- [MTU3 and MTU4]
|
||||
- Through interlocking with MTU0, a mode for driving AC synchronous
|
||||
motors (brushless DC motors) by using complementary PWM output and
|
||||
reset-synchronized PWM output is settable and allows the selection
|
||||
of two types of waveform output (chopping or level).
|
||||
of two types of waveform output (chopping or level)
|
||||
- [MTU5]
|
||||
- Capable of operation as a dead-time compensation counter.
|
||||
- Capable of operation as a dead-time compensation counter
|
||||
- [MTU0/MTU5, MTU1, MTU2, and MTU8]
|
||||
- 32-bit phase counting mode specifiable by combining MTU1 and MTU2 and
|
||||
through interlocked operation with MTU0/MTU5 and MTU8.
|
||||
through interlocked operation with MTU0/MTU5 and MTU8
|
||||
- Interrupt-skipping function
|
||||
- In complementary PWM mode, interrupts on crests and troughs of counter
|
||||
values and triggers to start conversion by the A/D converter can be
|
||||
skipped.
|
||||
skipped
|
||||
- Interrupt sources: 43 sources.
|
||||
- Buffer operation:
|
||||
- Automatic transfer of register data (transfer from the buffer
|
||||
|
|
@ -68,9 +68,9 @@ description: |
|
|||
- A/D converter start triggers can be generated
|
||||
- A/D converter start request delaying function enables A/D converter
|
||||
to be started with any desired timing and to be synchronized with
|
||||
PWM output.
|
||||
PWM output
|
||||
- Low power consumption function
|
||||
- The MTU3a can be placed in the module-stop state.
|
||||
- The MTU3a can be placed in the module-stop state
|
||||
|
||||
There are two phase counting modes. 16-bit phase counting mode in which
|
||||
MTU1 and MTU2 operate independently, and cascade connection 32-bit phase
|
||||
|
|
@ -109,6 +109,7 @@ properties:
|
|||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-mtu3 # RZ/{G2UL,Five}
|
||||
- renesas,r9a07g044-mtu3 # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-mtu3 # RZ/V2L
|
||||
- const: renesas,rz-mtu3
|
||||
|
|
@ -169,27 +170,27 @@ properties:
|
|||
- const: tgib0
|
||||
- const: tgic0
|
||||
- const: tgid0
|
||||
- const: tgiv0
|
||||
- const: tciv0
|
||||
- const: tgie0
|
||||
- const: tgif0
|
||||
- const: tgia1
|
||||
- const: tgib1
|
||||
- const: tgiv1
|
||||
- const: tgiu1
|
||||
- const: tciv1
|
||||
- const: tciu1
|
||||
- const: tgia2
|
||||
- const: tgib2
|
||||
- const: tgiv2
|
||||
- const: tgiu2
|
||||
- const: tciv2
|
||||
- const: tciu2
|
||||
- const: tgia3
|
||||
- const: tgib3
|
||||
- const: tgic3
|
||||
- const: tgid3
|
||||
- const: tgiv3
|
||||
- const: tciv3
|
||||
- const: tgia4
|
||||
- const: tgib4
|
||||
- const: tgic4
|
||||
- const: tgid4
|
||||
- const: tgiv4
|
||||
- const: tciv4
|
||||
- const: tgiu5
|
||||
- const: tgiv5
|
||||
- const: tgiw5
|
||||
|
|
@ -197,18 +198,18 @@ properties:
|
|||
- const: tgib6
|
||||
- const: tgic6
|
||||
- const: tgid6
|
||||
- const: tgiv6
|
||||
- const: tciv6
|
||||
- const: tgia7
|
||||
- const: tgib7
|
||||
- const: tgic7
|
||||
- const: tgid7
|
||||
- const: tgiv7
|
||||
- const: tciv7
|
||||
- const: tgia8
|
||||
- const: tgib8
|
||||
- const: tgic8
|
||||
- const: tgid8
|
||||
- const: tgiv8
|
||||
- const: tgiu8
|
||||
- const: tciv8
|
||||
- const: tciu8
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
|
@ -285,16 +286,16 @@ examples:
|
|||
<GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0",
|
||||
interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tciv0", "tgie0",
|
||||
"tgif0",
|
||||
"tgia1", "tgib1", "tgiv1", "tgiu1",
|
||||
"tgia2", "tgib2", "tgiv2", "tgiu2",
|
||||
"tgia3", "tgib3", "tgic3", "tgid3", "tgiv3",
|
||||
"tgia4", "tgib4", "tgic4", "tgid4", "tgiv4",
|
||||
"tgia1", "tgib1", "tciv1", "tciu1",
|
||||
"tgia2", "tgib2", "tciv2", "tciu2",
|
||||
"tgia3", "tgib3", "tgic3", "tgid3", "tciv3",
|
||||
"tgia4", "tgib4", "tgic4", "tgid4", "tciv4",
|
||||
"tgiu5", "tgiv5", "tgiw5",
|
||||
"tgia6", "tgib6", "tgic6", "tgid6", "tgiv6",
|
||||
"tgia7", "tgib7", "tgic7", "tgid7", "tgiv7",
|
||||
"tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8";
|
||||
"tgia6", "tgib6", "tgic6", "tgid6", "tciv6",
|
||||
"tgia7", "tgib7", "tgic7", "tgid7", "tciv7",
|
||||
"tgia8", "tgib8", "tgic8", "tgid8", "tciv8", "tciu8";
|
||||
clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
|
||||
|
|
|
|||
|
|
@ -732,4 +732,15 @@ config GOLDFISH_TIMER
|
|||
help
|
||||
Support for the timer/counter of goldfish-rtc
|
||||
|
||||
config EP93XX_TIMER
|
||||
bool "Cirrus Logic ep93xx timer driver" if COMPILE_TEST
|
||||
depends on ARCH_EP93XX
|
||||
depends on GENERIC_CLOCKEVENTS
|
||||
depends on HAS_IOMEM
|
||||
select CLKSRC_MMIO
|
||||
select TIMER_OF
|
||||
help
|
||||
Enables support for the Cirrus Logic timer block
|
||||
EP93XX.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -89,3 +89,4 @@ obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o
|
|||
obj-$(CONFIG_GOLDFISH_TIMER) += timer-goldfish.o
|
||||
obj-$(CONFIG_GXP_TIMER) += timer-gxp.o
|
||||
obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o
|
||||
obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
|
|||
writel(mck_divisor_idx /* likely divide-by-8 */
|
||||
| ATMEL_TC_WAVE
|
||||
| ATMEL_TC_WAVESEL_UP /* free-run */
|
||||
| ATMEL_TC_ASWTRG_SET /* TIOA0 rises at software trigger */
|
||||
| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
|
||||
| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
|
||||
tcaddr + ATMEL_TC_REG(0, CMR));
|
||||
|
|
|
|||
190
drivers/clocksource/timer-ep93xx.c
Normal file
190
drivers/clocksource/timer-ep93xx.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Cirrus Logic EP93xx timer driver.
|
||||
* Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
*
|
||||
* Based on a rewrite of arch/arm/mach-ep93xx/timer.c:
|
||||
*/
|
||||
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sched_clock.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
/*************************************************************************
|
||||
* Timer handling for EP93xx
|
||||
*************************************************************************
|
||||
* The ep93xx has four internal timers. Timers 1, 2 (both 16 bit) and
|
||||
* 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate
|
||||
* an interrupt on underflow. Timer 4 (40 bit) counts down at 983.04 kHz,
|
||||
* is free-running, and can't generate interrupts.
|
||||
*
|
||||
* The 508 kHz timers are ideal for use for the timer interrupt, as the
|
||||
* most common values of HZ divide 508 kHz nicely. We pick the 32 bit
|
||||
* timer (timer 3) to get as long sleep intervals as possible when using
|
||||
* CONFIG_NO_HZ.
|
||||
*
|
||||
* The higher clock rate of timer 4 makes it a better choice than the
|
||||
* other timers for use as clock source and for sched_clock(), providing
|
||||
* a stable 40 bit time base.
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
#define EP93XX_TIMER1_LOAD 0x00
|
||||
#define EP93XX_TIMER1_VALUE 0x04
|
||||
#define EP93XX_TIMER1_CONTROL 0x08
|
||||
#define EP93XX_TIMER123_CONTROL_ENABLE BIT(7)
|
||||
#define EP93XX_TIMER123_CONTROL_MODE BIT(6)
|
||||
#define EP93XX_TIMER123_CONTROL_CLKSEL BIT(3)
|
||||
#define EP93XX_TIMER1_CLEAR 0x0c
|
||||
#define EP93XX_TIMER2_LOAD 0x20
|
||||
#define EP93XX_TIMER2_VALUE 0x24
|
||||
#define EP93XX_TIMER2_CONTROL 0x28
|
||||
#define EP93XX_TIMER2_CLEAR 0x2c
|
||||
/*
|
||||
* This read-only register contains the low word of the time stamp debug timer
|
||||
* ( Timer4). When this register is read, the high byte of the Timer4 counter is
|
||||
* saved in the Timer4ValueHigh register.
|
||||
*/
|
||||
#define EP93XX_TIMER4_VALUE_LOW 0x60
|
||||
#define EP93XX_TIMER4_VALUE_HIGH 0x64
|
||||
#define EP93XX_TIMER4_VALUE_HIGH_ENABLE BIT(8)
|
||||
#define EP93XX_TIMER3_LOAD 0x80
|
||||
#define EP93XX_TIMER3_VALUE 0x84
|
||||
#define EP93XX_TIMER3_CONTROL 0x88
|
||||
#define EP93XX_TIMER3_CLEAR 0x8c
|
||||
|
||||
#define EP93XX_TIMER123_RATE 508469
|
||||
#define EP93XX_TIMER4_RATE 983040
|
||||
|
||||
struct ep93xx_tcu {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static struct ep93xx_tcu *ep93xx_tcu;
|
||||
|
||||
static u64 ep93xx_clocksource_read(struct clocksource *c)
|
||||
{
|
||||
struct ep93xx_tcu *tcu = ep93xx_tcu;
|
||||
|
||||
return lo_hi_readq(tcu->base + EP93XX_TIMER4_VALUE_LOW) & GENMASK_ULL(39, 0);
|
||||
}
|
||||
|
||||
static u64 notrace ep93xx_read_sched_clock(void)
|
||||
{
|
||||
return ep93xx_clocksource_read(NULL);
|
||||
}
|
||||
|
||||
static int ep93xx_clkevt_set_next_event(unsigned long next,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
struct ep93xx_tcu *tcu = ep93xx_tcu;
|
||||
/* Default mode: periodic, off, 508 kHz */
|
||||
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
|
||||
EP93XX_TIMER123_CONTROL_CLKSEL;
|
||||
|
||||
/* Clear timer */
|
||||
writel(tmode, tcu->base + EP93XX_TIMER3_CONTROL);
|
||||
|
||||
/* Set next event */
|
||||
writel(next, tcu->base + EP93XX_TIMER3_LOAD);
|
||||
writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
|
||||
tcu->base + EP93XX_TIMER3_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep93xx_clkevt_shutdown(struct clock_event_device *evt)
|
||||
{
|
||||
struct ep93xx_tcu *tcu = ep93xx_tcu;
|
||||
/* Disable timer */
|
||||
writel(0, tcu->base + EP93XX_TIMER3_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clock_event_device ep93xx_clockevent = {
|
||||
.name = "timer1",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_state_shutdown = ep93xx_clkevt_shutdown,
|
||||
.set_state_oneshot = ep93xx_clkevt_shutdown,
|
||||
.tick_resume = ep93xx_clkevt_shutdown,
|
||||
.set_next_event = ep93xx_clkevt_set_next_event,
|
||||
.rating = 300,
|
||||
};
|
||||
|
||||
static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct ep93xx_tcu *tcu = ep93xx_tcu;
|
||||
struct clock_event_device *evt = dev_id;
|
||||
|
||||
/* Writing any value clears the timer interrupt */
|
||||
writel(1, tcu->base + EP93XX_TIMER3_CLEAR);
|
||||
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init ep93xx_timer_of_init(struct device_node *np)
|
||||
{
|
||||
int irq;
|
||||
unsigned long flags = IRQF_TIMER | IRQF_IRQPOLL;
|
||||
struct ep93xx_tcu *tcu;
|
||||
int ret;
|
||||
|
||||
tcu = kzalloc(sizeof(*tcu), GFP_KERNEL);
|
||||
if (!tcu)
|
||||
return -ENOMEM;
|
||||
|
||||
tcu->base = of_iomap(np, 0);
|
||||
if (!tcu->base) {
|
||||
pr_err("Can't remap registers\n");
|
||||
ret = -ENXIO;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ep93xx_tcu = tcu;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq == 0)
|
||||
irq = -EINVAL;
|
||||
if (irq < 0) {
|
||||
pr_err("EP93XX Timer Can't parse IRQ %d", irq);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Enable and register clocksource and sched_clock on timer 4 */
|
||||
writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
|
||||
tcu->base + EP93XX_TIMER4_VALUE_HIGH);
|
||||
clocksource_mmio_init(NULL, "timer4",
|
||||
EP93XX_TIMER4_RATE, 200, 40,
|
||||
ep93xx_clocksource_read);
|
||||
sched_clock_register(ep93xx_read_sched_clock, 40,
|
||||
EP93XX_TIMER4_RATE);
|
||||
|
||||
/* Set up clockevent on timer 3 */
|
||||
if (request_irq(irq, ep93xx_timer_interrupt, flags, "ep93xx timer",
|
||||
&ep93xx_clockevent))
|
||||
pr_err("Failed to request irq %d (ep93xx timer)\n", irq);
|
||||
|
||||
clockevents_config_and_register(&ep93xx_clockevent,
|
||||
EP93XX_TIMER123_RATE,
|
||||
1,
|
||||
UINT_MAX);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
kfree(tcu);
|
||||
return ret;
|
||||
}
|
||||
TIMER_OF_DECLARE(ep93xx_timer, "cirrus,ep9301-timer", ep93xx_timer_of_init);
|
||||
|
|
@ -434,12 +434,16 @@ static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type t
|
|||
return -ENOMEM;
|
||||
|
||||
imxtm->base = of_iomap(np, 0);
|
||||
if (!imxtm->base)
|
||||
return -ENXIO;
|
||||
if (!imxtm->base) {
|
||||
ret = -ENXIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
imxtm->irq = irq_of_parse_and_map(np, 0);
|
||||
if (imxtm->irq <= 0)
|
||||
return -EINVAL;
|
||||
if (imxtm->irq <= 0) {
|
||||
ret = -EINVAL;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
|
||||
|
||||
|
|
@ -452,11 +456,15 @@ static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type t
|
|||
|
||||
ret = _mxc_timer_init(imxtm);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_kfree;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
err_kfree:
|
||||
kfree(imxtm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init imx1_timer_init_dt(struct device_node *np)
|
||||
|
|
|
|||
|
|
@ -212,6 +212,10 @@ TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt);
|
|||
#ifdef CONFIG_ACPI
|
||||
static int __init riscv_timer_acpi_init(struct acpi_table_header *table)
|
||||
{
|
||||
struct acpi_table_rhct *rhct = (struct acpi_table_rhct *)table;
|
||||
|
||||
riscv_timer_cannot_wake_cpu = rhct->flags & ACPI_RHCT_TIMER_CANNOT_WAKEUP_CPU;
|
||||
|
||||
return riscv_timer_init_common();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,10 +256,8 @@ static int sun5i_timer_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Can't get IRQ\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ struct dmtimer {
|
|||
struct platform_device *pdev;
|
||||
struct list_head node;
|
||||
struct notifier_block nb;
|
||||
struct notifier_block fclk_nb;
|
||||
unsigned long fclk_rate;
|
||||
};
|
||||
|
||||
static u32 omap_reserved_systimers;
|
||||
|
|
@ -253,8 +255,7 @@ static inline void __omap_dm_timer_enable_posted(struct dmtimer *timer)
|
|||
timer->posted = OMAP_TIMER_POSTED;
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_stop(struct dmtimer *timer,
|
||||
unsigned long rate)
|
||||
static inline void __omap_dm_timer_stop(struct dmtimer *timer)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
|
|
@ -269,7 +270,7 @@ static inline void __omap_dm_timer_stop(struct dmtimer *timer,
|
|||
* Wait for functional clock period x 3.5 to make sure that
|
||||
* timer is stopped
|
||||
*/
|
||||
udelay(3500000 / rate + 1);
|
||||
udelay(3500000 / timer->fclk_rate + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -348,6 +349,21 @@ static int omap_timer_context_notifier(struct notifier_block *nb,
|
|||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int omap_timer_fclk_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct clk_notifier_data *clk_data = data;
|
||||
struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb);
|
||||
|
||||
switch (event) {
|
||||
case POST_RATE_CHANGE:
|
||||
timer->fclk_rate = clk_data->new_rate;
|
||||
return NOTIFY_OK;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int omap_dm_timer_reset(struct dmtimer *timer)
|
||||
{
|
||||
u32 l, timeout = 100000;
|
||||
|
|
@ -754,7 +770,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie)
|
|||
{
|
||||
struct dmtimer *timer;
|
||||
struct device *dev;
|
||||
unsigned long rate = 0;
|
||||
|
||||
timer = to_dmtimer(cookie);
|
||||
if (unlikely(!timer))
|
||||
|
|
@ -762,10 +777,7 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie)
|
|||
|
||||
dev = &timer->pdev->dev;
|
||||
|
||||
if (!timer->omap1)
|
||||
rate = clk_get_rate(timer->fclk);
|
||||
|
||||
__omap_dm_timer_stop(timer, rate);
|
||||
__omap_dm_timer_stop(timer);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
|
|
@ -1124,6 +1136,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
|||
timer->fclk = devm_clk_get(dev, "fck");
|
||||
if (IS_ERR(timer->fclk))
|
||||
return PTR_ERR(timer->fclk);
|
||||
|
||||
timer->fclk_nb.notifier_call = omap_timer_fclk_notifier;
|
||||
ret = devm_clk_notifier_register(dev, timer->fclk,
|
||||
&timer->fclk_nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
timer->fclk_rate = clk_get_rate(timer->fclk);
|
||||
} else {
|
||||
timer->fclk = ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user