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