162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Broadcom
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/clk.h>
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <dt-bindings/clock/bcm2835-aux.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define BCM2835_AUXIRQ		0x00
1462306a36Sopenharmony_ci#define BCM2835_AUXENB		0x04
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int bcm2835_aux_clk_probe(struct platform_device *pdev)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
1962306a36Sopenharmony_ci	struct clk_hw_onecell_data *onecell;
2062306a36Sopenharmony_ci	const char *parent;
2162306a36Sopenharmony_ci	struct clk *parent_clk;
2262306a36Sopenharmony_ci	void __iomem *reg, *gate;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	parent_clk = devm_clk_get(dev, NULL);
2562306a36Sopenharmony_ci	if (IS_ERR(parent_clk))
2662306a36Sopenharmony_ci		return PTR_ERR(parent_clk);
2762306a36Sopenharmony_ci	parent = __clk_get_name(parent_clk);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	reg = devm_platform_ioremap_resource(pdev, 0);
3062306a36Sopenharmony_ci	if (IS_ERR(reg))
3162306a36Sopenharmony_ci		return PTR_ERR(reg);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	onecell = devm_kmalloc(dev,
3462306a36Sopenharmony_ci			       struct_size(onecell, hws,
3562306a36Sopenharmony_ci					   BCM2835_AUX_CLOCK_COUNT),
3662306a36Sopenharmony_ci			       GFP_KERNEL);
3762306a36Sopenharmony_ci	if (!onecell)
3862306a36Sopenharmony_ci		return -ENOMEM;
3962306a36Sopenharmony_ci	onecell->num = BCM2835_AUX_CLOCK_COUNT;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	gate = reg + BCM2835_AUXENB;
4262306a36Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_UART] =
4362306a36Sopenharmony_ci		clk_hw_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_SPI1] =
4662306a36Sopenharmony_ci		clk_hw_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	onecell->hws[BCM2835_AUX_CLOCK_SPI2] =
4962306a36Sopenharmony_ci		clk_hw_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
5262306a36Sopenharmony_ci				      onecell);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const struct of_device_id bcm2835_aux_clk_of_match[] = {
5662306a36Sopenharmony_ci	{ .compatible = "brcm,bcm2835-aux", },
5762306a36Sopenharmony_ci	{},
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic struct platform_driver bcm2835_aux_clk_driver = {
6262306a36Sopenharmony_ci	.driver = {
6362306a36Sopenharmony_ci		.name = "bcm2835-aux-clk",
6462306a36Sopenharmony_ci		.of_match_table = bcm2835_aux_clk_of_match,
6562306a36Sopenharmony_ci	},
6662306a36Sopenharmony_ci	.probe          = bcm2835_aux_clk_probe,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_cibuiltin_platform_driver(bcm2835_aux_clk_driver);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciMODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
7162306a36Sopenharmony_ciMODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
72