18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Broadcom
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk.h>
78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
118c2ecf20Sopenharmony_ci#include <dt-bindings/clock/bcm2835-aux.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define BCM2835_AUXIRQ		0x00
148c2ecf20Sopenharmony_ci#define BCM2835_AUXENB		0x04
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int bcm2835_aux_clk_probe(struct platform_device *pdev)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
198c2ecf20Sopenharmony_ci	struct clk_hw_onecell_data *onecell;
208c2ecf20Sopenharmony_ci	const char *parent;
218c2ecf20Sopenharmony_ci	struct clk *parent_clk;
228c2ecf20Sopenharmony_ci	void __iomem *reg, *gate;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	parent_clk = devm_clk_get(dev, NULL);
258c2ecf20Sopenharmony_ci	if (IS_ERR(parent_clk))
268c2ecf20Sopenharmony_ci		return PTR_ERR(parent_clk);
278c2ecf20Sopenharmony_ci	parent = __clk_get_name(parent_clk);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	reg = devm_platform_ioremap_resource(pdev, 0);
308c2ecf20Sopenharmony_ci	if (IS_ERR(reg))
318c2ecf20Sopenharmony_ci		return PTR_ERR(reg);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	onecell = devm_kmalloc(dev,
348c2ecf20Sopenharmony_ci			       struct_size(onecell, hws,
358c2ecf20Sopenharmony_ci					   BCM2835_AUX_CLOCK_COUNT),
368c2ecf20Sopenharmony_ci			       GFP_KERNEL);
378c2ecf20Sopenharmony_ci	if (!onecell)
388c2ecf20Sopenharmony_ci		return -ENOMEM;
398c2ecf20Sopenharmony_ci	onecell->num = BCM2835_AUX_CLOCK_COUNT;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	gate = reg + BCM2835_AUXENB;
428c2ecf20Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_UART] =
438c2ecf20Sopenharmony_ci		clk_hw_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_SPI1] =
468c2ecf20Sopenharmony_ci		clk_hw_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_SPI2] =
498c2ecf20Sopenharmony_ci		clk_hw_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
528c2ecf20Sopenharmony_ci				      onecell);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic const struct of_device_id bcm2835_aux_clk_of_match[] = {
568c2ecf20Sopenharmony_ci	{ .compatible = "brcm,bcm2835-aux", },
578c2ecf20Sopenharmony_ci	{},
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic struct platform_driver bcm2835_aux_clk_driver = {
628c2ecf20Sopenharmony_ci	.driver = {
638c2ecf20Sopenharmony_ci		.name = "bcm2835-aux-clk",
648c2ecf20Sopenharmony_ci		.of_match_table = bcm2835_aux_clk_of_match,
658c2ecf20Sopenharmony_ci	},
668c2ecf20Sopenharmony_ci	.probe          = bcm2835_aux_clk_probe,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_cibuiltin_platform_driver(bcm2835_aux_clk_driver);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
718c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
728c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
73