cregit-Linux how code gets into the kernel

Release 4.7 drivers/clocksource/meson6_timer.c

/*
 * Amlogic Meson6 SoCs timer handling.
 *
 * Copyright (C) 2014 Carlo Caione <carlo@caione.org>
 *
 * Based on code from Amlogic, Inc
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2.  This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */

#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/sched_clock.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>


#define CED_ID			0

#define CSD_ID			4


#define TIMER_ISA_MUX		0

#define TIMER_ISA_VAL(t)	(((t) + 1) << 2)


#define TIMER_INPUT_BIT(t)	(2 * (t))

#define TIMER_ENABLE_BIT(t)	(16 + (t))

#define TIMER_PERIODIC_BIT(t)	(12 + (t))


#define TIMER_CED_INPUT_MASK	(3UL << TIMER_INPUT_BIT(CED_ID))

#define TIMER_CSD_INPUT_MASK	(7UL << TIMER_INPUT_BIT(CSD_ID))


#define TIMER_CED_UNIT_1US	0

#define TIMER_CSD_UNIT_1US	1


static void __iomem *timer_base;


static u64 notrace meson6_timer_sched_read(void) { return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID)); }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione23100.00%1100.00%
Total23100.00%1100.00%


static void meson6_clkevt_time_stop(unsigned char timer) { u32 val = readl(timer_base + TIMER_ISA_MUX); writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione35100.00%1100.00%
Total35100.00%1100.00%


static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay) { writel(delay, timer_base + TIMER_ISA_VAL(timer)); }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione26100.00%1100.00%
Total26100.00%1100.00%


static void meson6_clkevt_time_start(unsigned char timer, bool periodic) { u32 val = readl(timer_base + TIMER_ISA_MUX); if (periodic) val |= TIMER_PERIODIC_BIT(timer); else val &= ~TIMER_PERIODIC_BIT(timer); writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione57100.00%1100.00%
Total57100.00%1100.00%


static int meson6_shutdown(struct clock_event_device *evt) { meson6_clkevt_time_stop(CED_ID); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione1263.16%150.00%
viresh kumarviresh kumar736.84%150.00%
Total19100.00%2100.00%


static int meson6_set_oneshot(struct clock_event_device *evt) { meson6_clkevt_time_stop(CED_ID); meson6_clkevt_time_start(CED_ID, false); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
viresh kumarviresh kumar1661.54%150.00%
carlo caionecarlo caione1038.46%150.00%
Total26100.00%2100.00%


static int meson6_set_periodic(struct clock_event_device *evt) { meson6_clkevt_time_stop(CED_ID); meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1); meson6_clkevt_time_start(CED_ID, true); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
viresh kumarviresh kumar2259.46%150.00%
carlo caionecarlo caione1540.54%150.00%
Total37100.00%2100.00%


static int meson6_clkevt_next_event(unsigned long evt, struct clock_event_device *unused) { meson6_clkevt_time_stop(CED_ID); meson6_clkevt_time_setup(CED_ID, evt); meson6_clkevt_time_start(CED_ID, false); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione37100.00%1100.00%
Total37100.00%1100.00%

static struct clock_event_device meson6_clockevent = { .name = "meson6_tick", .rating = 400, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_state_shutdown = meson6_shutdown, .set_state_periodic = meson6_set_periodic, .set_state_oneshot = meson6_set_oneshot, .tick_resume = meson6_shutdown, .set_next_event = meson6_clkevt_next_event, };
static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = (struct clock_event_device *)dev_id; evt->event_handler(evt); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione35100.00%1100.00%
Total35100.00%1100.00%

static struct irqaction meson6_timer_irq = { .name = "meson6_timer", .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = meson6_timer_interrupt, .dev_id = &meson6_clockevent, };
static void __init meson6_timer_init(struct device_node *node) { u32 val; int ret, irq; timer_base = of_io_request_and_map(node, 0, "meson6-timer"); if (IS_ERR(timer_base)) panic("Can't map registers"); irq = irq_of_parse_and_map(node, 0); if (irq <= 0) panic("Can't parse IRQ"); /* Set 1us for timer E */ val = readl(timer_base + TIMER_ISA_MUX); val &= ~TIMER_CSD_INPUT_MASK; val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID); writel(val, timer_base + TIMER_ISA_MUX); sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC); clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name, 1000 * 1000, 300, 32, clocksource_mmio_readl_up); /* Timer A base 1us */ val &= ~TIMER_CED_INPUT_MASK; val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID); writel(val, timer_base + TIMER_ISA_MUX); /* Stop the timer A */ meson6_clkevt_time_stop(CED_ID); ret = setup_irq(irq, &meson6_timer_irq); if (ret) pr_warn("failed to setup irq %d\n", irq); meson6_clockevent.cpumask = cpu_possible_mask; meson6_clockevent.irq = irq; clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC, 1, 0xfffe); }

Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione204100.00%1100.00%
Total204100.00%1100.00%

CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", meson6_timer_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
carlo caionecarlo caione61590.84%150.00%
viresh kumarviresh kumar629.16%150.00%
Total677100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}