brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · 419a886 Raw
132 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Clocksource using the Low Power Timer found in the Low Power Controller (LPC)4 *5 * Copyright (C) 2015 STMicroelectronics – All Rights Reserved6 *7 * Author(s): Francesco Virlinzi <francesco.virlinzi@st.com>8 *	      Ajit Pal Singh <ajitpal.singh@st.com>9 */10 11#include <linux/clk.h>12#include <linux/clocksource.h>13#include <linux/init.h>14#include <linux/of_address.h>15#include <linux/sched_clock.h>16#include <linux/slab.h>17 18#include <dt-bindings/mfd/st-lpc.h>19 20/* Low Power Timer */21#define LPC_LPT_LSB_OFF		0x40022#define LPC_LPT_MSB_OFF		0x40423#define LPC_LPT_START_OFF	0x40824 25static struct st_clksrc_ddata {26	struct clk		*clk;27	void __iomem		*base;28} ddata;29 30static void __init st_clksrc_reset(void)31{32	writel_relaxed(0, ddata.base + LPC_LPT_START_OFF);33	writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF);34	writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF);35	writel_relaxed(1, ddata.base + LPC_LPT_START_OFF);36}37 38static u64 notrace st_clksrc_sched_clock_read(void)39{40	return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF);41}42 43static int __init st_clksrc_init(void)44{45	unsigned long rate;46	int ret;47 48	st_clksrc_reset();49 50	rate = clk_get_rate(ddata.clk);51 52	sched_clock_register(st_clksrc_sched_clock_read, 32, rate);53 54	ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF,55				    "clksrc-st-lpc", rate, 300, 32,56				    clocksource_mmio_readl_up);57	if (ret) {58		pr_err("clksrc-st-lpc: Failed to register clocksource\n");59		return ret;60	}61 62	return 0;63}64 65static int __init st_clksrc_setup_clk(struct device_node *np)66{67	struct clk *clk;68 69	clk = of_clk_get(np, 0);70	if (IS_ERR(clk)) {71		pr_err("clksrc-st-lpc: Failed to get LPC clock\n");72		return PTR_ERR(clk);73	}74 75	if (clk_prepare_enable(clk)) {76		pr_err("clksrc-st-lpc: Failed to enable LPC clock\n");77		return -EINVAL;78	}79 80	if (!clk_get_rate(clk)) {81		pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n");82		clk_disable_unprepare(clk);83		return -EINVAL;84	}85 86	ddata.clk = clk;87 88	return 0;89}90 91static int __init st_clksrc_of_register(struct device_node *np)92{93	int ret;94	uint32_t mode;95 96	ret = of_property_read_u32(np, "st,lpc-mode", &mode);97	if (ret) {98		pr_err("clksrc-st-lpc: An LPC mode must be provided\n");99		return ret;100	}101 102	/* LPC can either run as a Clocksource or in RTC or WDT mode */103	if (mode != ST_LPC_MODE_CLKSRC)104		return 0;105 106	ddata.base = of_iomap(np, 0);107	if (!ddata.base) {108		pr_err("clksrc-st-lpc: Unable to map iomem\n");109		return -ENXIO;110	}111 112	ret = st_clksrc_setup_clk(np);113	if (ret) {114		iounmap(ddata.base);115		return ret;116	}117 118	ret = st_clksrc_init();119	if (ret) {120		clk_disable_unprepare(ddata.clk);121		clk_put(ddata.clk);122		iounmap(ddata.base);123		return ret;124	}125 126	pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n",127		clk_get_rate(ddata.clk));128 129	return ret;130}131TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);132