162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BCM63268 Timer Clock and Reset Controller Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2023 Álvaro Fernández Rojas <noltari@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk-provider.h> 962306a36Sopenharmony_ci#include <linux/container_of.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/reset-controller.h> 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <dt-bindings/clock/bcm63268-clock.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define BCM63268_TIMER_RESET_SLEEP_MIN_US 10000 2062306a36Sopenharmony_ci#define BCM63268_TIMER_RESET_SLEEP_MAX_US 20000 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct bcm63268_tclkrst_hw { 2362306a36Sopenharmony_ci void __iomem *regs; 2462306a36Sopenharmony_ci spinlock_t lock; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci struct reset_controller_dev rcdev; 2762306a36Sopenharmony_ci struct clk_hw_onecell_data data; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct bcm63268_tclk_table_entry { 3162306a36Sopenharmony_ci const char * const name; 3262306a36Sopenharmony_ci u8 bit; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic const struct bcm63268_tclk_table_entry bcm63268_timer_clocks[] = { 3662306a36Sopenharmony_ci { 3762306a36Sopenharmony_ci .name = "ephy1", 3862306a36Sopenharmony_ci .bit = BCM63268_TCLK_EPHY1, 3962306a36Sopenharmony_ci }, { 4062306a36Sopenharmony_ci .name = "ephy2", 4162306a36Sopenharmony_ci .bit = BCM63268_TCLK_EPHY2, 4262306a36Sopenharmony_ci }, { 4362306a36Sopenharmony_ci .name = "ephy3", 4462306a36Sopenharmony_ci .bit = BCM63268_TCLK_EPHY3, 4562306a36Sopenharmony_ci }, { 4662306a36Sopenharmony_ci .name = "gphy1", 4762306a36Sopenharmony_ci .bit = BCM63268_TCLK_GPHY1, 4862306a36Sopenharmony_ci }, { 4962306a36Sopenharmony_ci .name = "dsl", 5062306a36Sopenharmony_ci .bit = BCM63268_TCLK_DSL, 5162306a36Sopenharmony_ci }, { 5262306a36Sopenharmony_ci .name = "wakeon_ephy", 5362306a36Sopenharmony_ci .bit = BCM63268_TCLK_WAKEON_EPHY, 5462306a36Sopenharmony_ci }, { 5562306a36Sopenharmony_ci .name = "wakeon_dsl", 5662306a36Sopenharmony_ci .bit = BCM63268_TCLK_WAKEON_DSL, 5762306a36Sopenharmony_ci }, { 5862306a36Sopenharmony_ci .name = "fap1_pll", 5962306a36Sopenharmony_ci .bit = BCM63268_TCLK_FAP1, 6062306a36Sopenharmony_ci }, { 6162306a36Sopenharmony_ci .name = "fap2_pll", 6262306a36Sopenharmony_ci .bit = BCM63268_TCLK_FAP2, 6362306a36Sopenharmony_ci }, { 6462306a36Sopenharmony_ci .name = "uto_50", 6562306a36Sopenharmony_ci .bit = BCM63268_TCLK_UTO_50, 6662306a36Sopenharmony_ci }, { 6762306a36Sopenharmony_ci .name = "uto_extin", 6862306a36Sopenharmony_ci .bit = BCM63268_TCLK_UTO_EXTIN, 6962306a36Sopenharmony_ci }, { 7062306a36Sopenharmony_ci .name = "usb_ref", 7162306a36Sopenharmony_ci .bit = BCM63268_TCLK_USB_REF, 7262306a36Sopenharmony_ci }, { 7362306a36Sopenharmony_ci /* sentinel */ 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline struct bcm63268_tclkrst_hw * 7862306a36Sopenharmony_cito_bcm63268_timer_reset(struct reset_controller_dev *rcdev) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return container_of(rcdev, struct bcm63268_tclkrst_hw, rcdev); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int bcm63268_timer_reset_update(struct reset_controller_dev *rcdev, 8462306a36Sopenharmony_ci unsigned long id, bool assert) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); 8762306a36Sopenharmony_ci unsigned long flags; 8862306a36Sopenharmony_ci uint32_t val; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci spin_lock_irqsave(&reset->lock, flags); 9162306a36Sopenharmony_ci val = __raw_readl(reset->regs); 9262306a36Sopenharmony_ci if (assert) 9362306a36Sopenharmony_ci val &= ~BIT(id); 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci val |= BIT(id); 9662306a36Sopenharmony_ci __raw_writel(val, reset->regs); 9762306a36Sopenharmony_ci spin_unlock_irqrestore(&reset->lock, flags); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int bcm63268_timer_reset_assert(struct reset_controller_dev *rcdev, 10362306a36Sopenharmony_ci unsigned long id) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return bcm63268_timer_reset_update(rcdev, id, true); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int bcm63268_timer_reset_deassert(struct reset_controller_dev *rcdev, 10962306a36Sopenharmony_ci unsigned long id) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return bcm63268_timer_reset_update(rcdev, id, false); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int bcm63268_timer_reset_reset(struct reset_controller_dev *rcdev, 11562306a36Sopenharmony_ci unsigned long id) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci bcm63268_timer_reset_update(rcdev, id, true); 11862306a36Sopenharmony_ci usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, 11962306a36Sopenharmony_ci BCM63268_TIMER_RESET_SLEEP_MAX_US); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci bcm63268_timer_reset_update(rcdev, id, false); 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Ensure component is taken out reset state by sleeping also after 12462306a36Sopenharmony_ci * deasserting the reset. Otherwise, the component may not be ready 12562306a36Sopenharmony_ci * for operation. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, 12862306a36Sopenharmony_ci BCM63268_TIMER_RESET_SLEEP_MAX_US); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int bcm63268_timer_reset_status(struct reset_controller_dev *rcdev, 13462306a36Sopenharmony_ci unsigned long id) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return !(__raw_readl(reset->regs) & BIT(id)); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct reset_control_ops bcm63268_timer_reset_ops = { 14262306a36Sopenharmony_ci .assert = bcm63268_timer_reset_assert, 14362306a36Sopenharmony_ci .deassert = bcm63268_timer_reset_deassert, 14462306a36Sopenharmony_ci .reset = bcm63268_timer_reset_reset, 14562306a36Sopenharmony_ci .status = bcm63268_timer_reset_status, 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int bcm63268_tclk_probe(struct platform_device *pdev) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 15162306a36Sopenharmony_ci const struct bcm63268_tclk_table_entry *entry; 15262306a36Sopenharmony_ci struct bcm63268_tclkrst_hw *hw; 15362306a36Sopenharmony_ci struct clk_hw *clk; 15462306a36Sopenharmony_ci u8 maxbit = 0; 15562306a36Sopenharmony_ci int i, ret; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci for (entry = bcm63268_timer_clocks; entry->name; entry++) 15862306a36Sopenharmony_ci maxbit = max(maxbit, entry->bit); 15962306a36Sopenharmony_ci maxbit++; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), 16262306a36Sopenharmony_ci GFP_KERNEL); 16362306a36Sopenharmony_ci if (!hw) 16462306a36Sopenharmony_ci return -ENOMEM; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci platform_set_drvdata(pdev, hw); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spin_lock_init(&hw->lock); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci hw->data.num = maxbit; 17162306a36Sopenharmony_ci for (i = 0; i < maxbit; i++) 17262306a36Sopenharmony_ci hw->data.hws[i] = ERR_PTR(-ENODEV); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci hw->regs = devm_platform_ioremap_resource(pdev, 0); 17562306a36Sopenharmony_ci if (IS_ERR(hw->regs)) 17662306a36Sopenharmony_ci return PTR_ERR(hw->regs); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for (entry = bcm63268_timer_clocks; entry->name; entry++) { 17962306a36Sopenharmony_ci clk = devm_clk_hw_register_gate(dev, entry->name, NULL, 0, 18062306a36Sopenharmony_ci hw->regs, entry->bit, 18162306a36Sopenharmony_ci CLK_GATE_BIG_ENDIAN, 18262306a36Sopenharmony_ci &hw->lock); 18362306a36Sopenharmony_ci if (IS_ERR(clk)) 18462306a36Sopenharmony_ci return PTR_ERR(clk); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci hw->data.hws[entry->bit] = clk; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 19062306a36Sopenharmony_ci &hw->data); 19162306a36Sopenharmony_ci if (ret) 19262306a36Sopenharmony_ci return ret; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci hw->rcdev.of_node = dev->of_node; 19562306a36Sopenharmony_ci hw->rcdev.ops = &bcm63268_timer_reset_ops; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = devm_reset_controller_register(dev, &hw->rcdev); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci dev_err(dev, "Failed to register reset controller\n"); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const struct of_device_id bcm63268_tclk_dt_ids[] = { 20562306a36Sopenharmony_ci { .compatible = "brcm,bcm63268-timer-clocks" }, 20662306a36Sopenharmony_ci { /* sentinel */ } 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic struct platform_driver bcm63268_tclk = { 21062306a36Sopenharmony_ci .probe = bcm63268_tclk_probe, 21162306a36Sopenharmony_ci .driver = { 21262306a36Sopenharmony_ci .name = "bcm63268-timer-clock", 21362306a36Sopenharmony_ci .of_match_table = bcm63268_tclk_dt_ids, 21462306a36Sopenharmony_ci }, 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_cibuiltin_platform_driver(bcm63268_tclk); 217