brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · e0ec333 Raw
184 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * JZ47xx SoCs TCU Operating System Timer driver4 *5 * Copyright (C) 2016 Maarten ter Huurne <maarten@treewalker.org>6 * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>7 */8 9#include <linux/clk.h>10#include <linux/clocksource.h>11#include <linux/mfd/ingenic-tcu.h>12#include <linux/mfd/syscon.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/pm.h>16#include <linux/regmap.h>17#include <linux/sched_clock.h>18 19#define TCU_OST_TCSR_MASK	0xffc020#define TCU_OST_TCSR_CNT_MD	BIT(15)21 22#define TCU_OST_CHANNEL		1523 24/*25 * The TCU_REG_OST_CNT{L,R} from <linux/mfd/ingenic-tcu.h> are only for the26 * regmap; these are for use with the __iomem pointer.27 */28#define OST_REG_CNTL		0x429#define OST_REG_CNTH		0x830 31struct ingenic_ost_soc_info {32	bool is64bit;33};34 35struct ingenic_ost {36	void __iomem *regs;37	struct clk *clk;38 39	struct clocksource cs;40};41 42static struct ingenic_ost *ingenic_ost;43 44static u64 notrace ingenic_ost_read_cntl(void)45{46	/* Read using __iomem pointer instead of regmap to avoid locking */47	return readl(ingenic_ost->regs + OST_REG_CNTL);48}49 50static u64 notrace ingenic_ost_read_cnth(void)51{52	/* Read using __iomem pointer instead of regmap to avoid locking */53	return readl(ingenic_ost->regs + OST_REG_CNTH);54}55 56static u64 notrace ingenic_ost_clocksource_readl(struct clocksource *cs)57{58	return ingenic_ost_read_cntl();59}60 61static u64 notrace ingenic_ost_clocksource_readh(struct clocksource *cs)62{63	return ingenic_ost_read_cnth();64}65 66static int __init ingenic_ost_probe(struct platform_device *pdev)67{68	const struct ingenic_ost_soc_info *soc_info;69	struct device *dev = &pdev->dev;70	struct ingenic_ost *ost;71	struct clocksource *cs;72	struct regmap *map;73	unsigned long rate;74	int err;75 76	soc_info = device_get_match_data(dev);77	if (!soc_info)78		return -EINVAL;79 80	ost = devm_kzalloc(dev, sizeof(*ost), GFP_KERNEL);81	if (!ost)82		return -ENOMEM;83 84	ingenic_ost = ost;85 86	ost->regs = devm_platform_ioremap_resource(pdev, 0);87	if (IS_ERR(ost->regs))88		return PTR_ERR(ost->regs);89 90	map = device_node_to_regmap(dev->parent->of_node);91	if (IS_ERR(map)) {92		dev_err(dev, "regmap not found");93		return PTR_ERR(map);94	}95 96	ost->clk = devm_clk_get_enabled(dev, "ost");97	if (IS_ERR(ost->clk))98		return PTR_ERR(ost->clk);99 100	/* Clear counter high/low registers */101	if (soc_info->is64bit)102		regmap_write(map, TCU_REG_OST_CNTL, 0);103	regmap_write(map, TCU_REG_OST_CNTH, 0);104 105	/* Don't reset counter at compare value. */106	regmap_update_bits(map, TCU_REG_OST_TCSR,107			   TCU_OST_TCSR_MASK, TCU_OST_TCSR_CNT_MD);108 109	rate = clk_get_rate(ost->clk);110 111	/* Enable OST TCU channel */112	regmap_write(map, TCU_REG_TESR, BIT(TCU_OST_CHANNEL));113 114	cs = &ost->cs;115	cs->name	= "ingenic-ost";116	cs->rating	= 320;117	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;118	cs->mask	= CLOCKSOURCE_MASK(32);119 120	if (soc_info->is64bit)121		cs->read = ingenic_ost_clocksource_readl;122	else123		cs->read = ingenic_ost_clocksource_readh;124 125	err = clocksource_register_hz(cs, rate);126	if (err) {127		dev_err(dev, "clocksource registration failed");128		return err;129	}130 131	if (soc_info->is64bit)132		sched_clock_register(ingenic_ost_read_cntl, 32, rate);133	else134		sched_clock_register(ingenic_ost_read_cnth, 32, rate);135 136	return 0;137}138 139static int ingenic_ost_suspend(struct device *dev)140{141	struct ingenic_ost *ost = dev_get_drvdata(dev);142 143	clk_disable(ost->clk);144 145	return 0;146}147 148static int ingenic_ost_resume(struct device *dev)149{150	struct ingenic_ost *ost = dev_get_drvdata(dev);151 152	return clk_enable(ost->clk);153}154 155static const struct dev_pm_ops ingenic_ost_pm_ops = {156	/* _noirq: We want the OST clock to be gated last / ungated first */157	.suspend_noirq = ingenic_ost_suspend,158	.resume_noirq  = ingenic_ost_resume,159};160 161static const struct ingenic_ost_soc_info jz4725b_ost_soc_info = {162	.is64bit = false,163};164 165static const struct ingenic_ost_soc_info jz4760b_ost_soc_info = {166	.is64bit = true,167};168 169static const struct of_device_id ingenic_ost_of_match[] = {170	{ .compatible = "ingenic,jz4725b-ost", .data = &jz4725b_ost_soc_info, },171	{ .compatible = "ingenic,jz4760b-ost", .data = &jz4760b_ost_soc_info, },172	{ .compatible = "ingenic,jz4770-ost", .data = &jz4760b_ost_soc_info, },173	{ }174};175 176static struct platform_driver ingenic_ost_driver = {177	.driver = {178		.name = "ingenic-ost",179		.pm = pm_sleep_ptr(&ingenic_ost_pm_ops),180		.of_match_table = ingenic_ost_of_match,181	},182};183builtin_platform_driver_probe(ingenic_ost_driver, ingenic_ost_probe);184