timer-digicolor.c (5044B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Conexant Digicolor timer driver 4 * 5 * Author: Baruch Siach <baruch@tkos.co.il> 6 * 7 * Copyright (C) 2014 Paradox Innovation Ltd. 8 * 9 * Based on: 10 * Allwinner SoCs hstimer driver 11 * 12 * Copyright (C) 2013 Maxime Ripard 13 * 14 * Maxime Ripard <maxime.ripard@free-electrons.com> 15 */ 16 17/* 18 * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to 19 * "Timer H". Timer A is the only one with watchdog support, so it is dedicated 20 * to the watchdog driver. This driver uses Timer B for sched_clock(), and 21 * Timer C for clockevents. 22 */ 23 24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 25 26#include <linux/clk.h> 27#include <linux/clockchips.h> 28#include <linux/interrupt.h> 29#include <linux/irq.h> 30#include <linux/irqreturn.h> 31#include <linux/sched/clock.h> 32#include <linux/sched_clock.h> 33#include <linux/of.h> 34#include <linux/of_address.h> 35#include <linux/of_irq.h> 36 37enum { 38 TIMER_A, 39 TIMER_B, 40 TIMER_C, 41 TIMER_D, 42 TIMER_E, 43 TIMER_F, 44 TIMER_G, 45 TIMER_H, 46}; 47 48#define CONTROL(t) ((t)*8) 49#define COUNT(t) ((t)*8 + 4) 50 51#define CONTROL_DISABLE 0 52#define CONTROL_ENABLE BIT(0) 53#define CONTROL_MODE(m) ((m) << 4) 54#define CONTROL_MODE_ONESHOT CONTROL_MODE(1) 55#define CONTROL_MODE_PERIODIC CONTROL_MODE(2) 56 57struct digicolor_timer { 58 struct clock_event_device ce; 59 void __iomem *base; 60 u32 ticks_per_jiffy; 61 int timer_id; /* one of TIMER_* */ 62}; 63 64static struct digicolor_timer *dc_timer(struct clock_event_device *ce) 65{ 66 return container_of(ce, struct digicolor_timer, ce); 67} 68 69static inline void dc_timer_disable(struct clock_event_device *ce) 70{ 71 struct digicolor_timer *dt = dc_timer(ce); 72 writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id)); 73} 74 75static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode) 76{ 77 struct digicolor_timer *dt = dc_timer(ce); 78 writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id)); 79} 80 81static inline void dc_timer_set_count(struct clock_event_device *ce, 82 unsigned long count) 83{ 84 struct digicolor_timer *dt = dc_timer(ce); 85 writel(count, dt->base + COUNT(dt->timer_id)); 86} 87 88static int digicolor_clkevt_shutdown(struct clock_event_device *ce) 89{ 90 dc_timer_disable(ce); 91 return 0; 92} 93 94static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce) 95{ 96 dc_timer_disable(ce); 97 dc_timer_enable(ce, CONTROL_MODE_ONESHOT); 98 return 0; 99} 100 101static int digicolor_clkevt_set_periodic(struct clock_event_device *ce) 102{ 103 struct digicolor_timer *dt = dc_timer(ce); 104 105 dc_timer_disable(ce); 106 dc_timer_set_count(ce, dt->ticks_per_jiffy); 107 dc_timer_enable(ce, CONTROL_MODE_PERIODIC); 108 return 0; 109} 110 111static int digicolor_clkevt_next_event(unsigned long evt, 112 struct clock_event_device *ce) 113{ 114 dc_timer_disable(ce); 115 dc_timer_set_count(ce, evt); 116 dc_timer_enable(ce, CONTROL_MODE_ONESHOT); 117 118 return 0; 119} 120 121static struct digicolor_timer dc_timer_dev = { 122 .ce = { 123 .name = "digicolor_tick", 124 .rating = 340, 125 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 126 .set_state_shutdown = digicolor_clkevt_shutdown, 127 .set_state_periodic = digicolor_clkevt_set_periodic, 128 .set_state_oneshot = digicolor_clkevt_set_oneshot, 129 .tick_resume = digicolor_clkevt_shutdown, 130 .set_next_event = digicolor_clkevt_next_event, 131 }, 132 .timer_id = TIMER_C, 133}; 134 135static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id) 136{ 137 struct clock_event_device *evt = dev_id; 138 139 evt->event_handler(evt); 140 141 return IRQ_HANDLED; 142} 143 144static u64 notrace digicolor_timer_sched_read(void) 145{ 146 return ~readl(dc_timer_dev.base + COUNT(TIMER_B)); 147} 148 149static int __init digicolor_timer_init(struct device_node *node) 150{ 151 unsigned long rate; 152 struct clk *clk; 153 int ret, irq; 154 155 /* 156 * timer registers are shared with the watchdog timer; 157 * don't map exclusively 158 */ 159 dc_timer_dev.base = of_iomap(node, 0); 160 if (!dc_timer_dev.base) { 161 pr_err("Can't map registers\n"); 162 return -ENXIO; 163 } 164 165 irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id); 166 if (irq <= 0) { 167 pr_err("Can't parse IRQ\n"); 168 return -EINVAL; 169 } 170 171 clk = of_clk_get(node, 0); 172 if (IS_ERR(clk)) { 173 pr_err("Can't get timer clock\n"); 174 return PTR_ERR(clk); 175 } 176 clk_prepare_enable(clk); 177 rate = clk_get_rate(clk); 178 dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); 179 180 writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B)); 181 writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B)); 182 writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B)); 183 184 sched_clock_register(digicolor_timer_sched_read, 32, rate); 185 clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name, 186 rate, 340, 32, clocksource_mmio_readl_down); 187 188 ret = request_irq(irq, digicolor_timer_interrupt, 189 IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC", 190 &dc_timer_dev.ce); 191 if (ret) { 192 pr_warn("request of timer irq %d failed (%d)\n", irq, ret); 193 return ret; 194 } 195 196 dc_timer_dev.ce.cpumask = cpu_possible_mask; 197 dc_timer_dev.ce.irq = irq; 198 199 clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff); 200 201 return 0; 202} 203TIMER_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", 204 digicolor_timer_init);