From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B45536E465 for ; Tue, 17 Feb 2026 16:14:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771344875; cv=none; b=lwLuELQAmpuAWsTMPHvVy3cixnR/wVs3/Tu+ztEfXZDVSQ6yC2oI20r7jo8YlPyr8eX1lc+oZ7M40d4UZJ/A0BlRfttkj04w9TKbTk0gldDRhJpOyfkpXWpszycsBUYtphvatWE2qY31ZRdUD0Pffg7E5+gBycohSQzijVNXAx0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771344875; c=relaxed/simple; bh=IkiHYOkmy0pa6e7QVSjgzZ+NzAaF4Y7AEwFqt5hd0c4=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=E6m7ttEAERo/ZoGYvN4ZsqdwfYVfLUw47VRQHAJHJimSa7AM3UBgnXN45exmEYnHCJO30lT+gXnKIz/kcvg0Yoeej2BZ7zBxakkhXuYYVG0qjvEISxyM2k+HU8v5dsM5Ub35dCvJ0oCTSFiPXOTSeqJMnqLzSN+ZdaMV+PtcYbs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=L1W0yAMQ; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=Hvqrddyj; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="L1W0yAMQ"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="Hvqrddyj" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771344872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=OgLET0EyZlgFqcNgrcZaw4QB+5/hZb3RiyFXCQoJ30c=; b=L1W0yAMQX9I9IHstqs9qUSvp8CZOR6IIFDNzdmApuXPvCiDg3/vMt3vVHEbKc89o0dLqHu 8GK4qYOFJsJkU97mxg88B3Ibli3zrqdzYikLXyJETGBS56dVVGO3pRZzopqmBpDhgIT5pB hfmPzn8nay5Qy8O1vV72o5iXq0V7dWY= Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-173-f-UtUDaxMgiMJ_bqsEQQ0Q-1; Tue, 17 Feb 2026 11:14:29 -0500 X-MC-Unique: f-UtUDaxMgiMJ_bqsEQQ0Q-1 X-Mimecast-MFC-AGG-ID: f-UtUDaxMgiMJ_bqsEQQ0Q_1771344869 Received: by mail-qt1-f197.google.com with SMTP id d75a77b69052e-506b1524dfeso262355261cf.2 for ; Tue, 17 Feb 2026 08:14:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1771344869; x=1771949669; darn=vger.kernel.org; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:from:to:cc:subject:date :message-id:reply-to; bh=OgLET0EyZlgFqcNgrcZaw4QB+5/hZb3RiyFXCQoJ30c=; b=HvqrddyjWDo8UkoL7TDlNc/4zfpqlUdIVuyFQM+ZLVOEfqzg8YzuY/xflz/h48g8pr XRgVBaW/IrjTudfMMYLtL5SIX9B1JqlcPHUpDpuoB87gZT7GRo881LcSbfAE0bAWoWzp tKvRN/gPFkHlvNZca30RFfqid0FYdANCKaEe6c4lk+xFXQJPrAuvqkLroV0FJKq/EIwJ M1kfFei5Q5QnRgclreL2kyk0Qey5sQH7wnT5ZaNAyxgPDG9S+UnrU8aNFAx2rKkjh7nt acxyWavCoDh0iM06aMXzMNAPACANhrLNaQTbUI0PwdhFl2+4PsJb3+EAYJOL1YPgwxl6 fRWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771344869; x=1771949669; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=OgLET0EyZlgFqcNgrcZaw4QB+5/hZb3RiyFXCQoJ30c=; b=JDoJ72CIY1Wx7dCqod+ok1w26D9QRw6CSCTrgbhuymz3VvkVSXFWVlKKk6xyoDjZnD om7sxoI8CDU3oER7NU+vFIDdAAeKQiy3Q2Be9YfLd4ze5qLXhifOpyd3rh6/DxDni+vL U7nYoCb+nI/bJ3xHMbvQwGuNsx7hP3eQAUBM3oqgptKRqx6hjJcBdcAd8X+zcENt6yCK Auh+cUTItWt/e7JLu8ThMiWguaNGH18Aycka4VH5NRcOx0iNE9fXUwaYaaKqqtH0Ica5 lgmlSehLvdF+HGRP9G5stMEZ+vjtE1fvu0Kjr0wIJ8JpwpG8rWd2D5XsjraFWYojx0Zp pD9A== X-Forwarded-Encrypted: i=1; AJvYcCW46L/ELZBZZ+gMnz2adBxWFiYzgahwfTS+tWSUiw+nOTt6zMydJDvJRJ7GGXF5Q0AxT+0mWCYn5jtkOlU=@vger.kernel.org X-Gm-Message-State: AOJu0YxC1yM8OGKuS6cRRqCy5CB5ArguCZhzoaN5L+rKk0a7h3yZBuU9 S5Uz7kPS2eG/luArdHWFf1yOHhcgtQ61mXIUKLNAlsXT4BnSwitK6OQ8ki7zSUmAIj0pbRuBdNJ 3G7oaglkvz3j1vat7IgRwM1vzr5EK8XeQaNuv4lNK1/TkT3eZg+pkS8iCfnAnM+jVVg== X-Gm-Gg: AZuq6aLIWJwUZcFOphCV1pr0kWmgs8pMZF1VZg41c7lIKASnxASTwX+bwpx9Go1iEZ2 Mbsy/I/G/rMaK6SWtNyAupb8lMJSwn8G81weZXpy/Ti40/N0hV2kH9c5BiU3QgF9gt9P9SDle6X idp0hAMvoNP196YjQbdgGE9UOESJ0/oowDNRezu/hOq2w4aCg8nisCMZGvBSPFsm16KBYmy54v6 eoWuFAt2brENQnFKy2u64SepZ8cgxlJWOiob/4nXaKGdvFaj12qXVS38iyDmfw4AyGCVM1tL+oF 8MuC8+uv+ThtY9IKhUaDPluUnWBPgRO38qsYrz2kdTpaR1Wwg4QD6UIGCkLI+Iw+q0aWgOUUWYb qouq9IwmshpuaO+veC6yfxlv8g+WUUYD7DbGkxFSvcNlEFYP2Duv7k0Vw X-Received: by 2002:a05:622a:48b:b0:4eb:a8ba:947b with SMTP id d75a77b69052e-506a82a480cmr182108351cf.24.1771344868748; Tue, 17 Feb 2026 08:14:28 -0800 (PST) X-Received: by 2002:a05:622a:48b:b0:4eb:a8ba:947b with SMTP id d75a77b69052e-506a82a480cmr182107631cf.24.1771344868152; Tue, 17 Feb 2026 08:14:28 -0800 (PST) Received: from redhat.com (c-73-183-52-120.hsd1.pa.comcast.net. [73.183.52.120]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cb2b218258sm1561665685a.47.2026.02.17.08.14.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Feb 2026 08:14:27 -0800 (PST) Date: Tue, 17 Feb 2026 11:14:25 -0500 From: Brian Masney To: Anirudh Srinivasan Cc: Drew Fustini , Joel Stanley , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Philipp Zabel , linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org, joel@jms.id.au, fustini@kernel.org, mpe@kernel.org, mpe@oss.tenstorrent.com, npiggin@oss.tenstorrent.com, agross@kernel.org, agross@oss.tenstorrent.com Subject: Re: [PATCH v6 3/3] clk: tenstorrent: Add Atlantis clock controller driver Message-ID: References: <20260216-atlantis-clocks-v6-0-cb46d6a59c73@oss.tenstorrent.com> <20260216-atlantis-clocks-v6-3-cb46d6a59c73@oss.tenstorrent.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260216-atlantis-clocks-v6-3-cb46d6a59c73@oss.tenstorrent.com> User-Agent: Mutt/2.2.14 (2025-02-20) Hi Anirudh, On Mon, Feb 16, 2026 at 04:16:34PM -0600, Anirudh Srinivasan wrote: > Add driver for clock controller in Tenstorrent Atlantis SoC. This version > of the driver coves clocks from RCPU syscon. ...covers clocks.. > > 5 types of clocks generated by this controller: PLLs (PLLs > with bypass functionality and an additional Gate clk at output), Shared > Gates (Multiple Gate clks that share an enable bit), standard Muxes, > Dividers and Gates. All clocks are implemented using custom clk ops and > use the regmap interface associated with the syscon. All clocks are derived > from a 24 Mhz oscillator. > > The reset controller is also setup as an auxiliary device of the clock > controller. > > Signed-off-by: Anirudh Srinivasan > --- > MAINTAINERS | 1 + > drivers/clk/Kconfig | 1 + > drivers/clk/Makefile | 1 + > drivers/clk/tenstorrent/Kconfig | 14 + > drivers/clk/tenstorrent/Makefile | 3 + > drivers/clk/tenstorrent/atlantis-prcm.c | 901 ++++++++++++++++++++++++++++++++ > 6 files changed, 921 insertions(+) > > diff --git a/MAINTAINERS b/MAINTAINERS > index 93f4e860e589..b4aee846aa5e 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -22537,6 +22537,7 @@ T: git https://github.com/tenstorrent/linux.git > F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml > F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml > F: arch/riscv/boot/dts/tenstorrent/ > +F: drivers/clk/tenstorrent/ > F: drivers/reset/reset-tenstorrent-atlantis.c > F: include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h > > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig > index 3a1611008e48..643084887257 100644 > --- a/drivers/clk/Kconfig > +++ b/drivers/clk/Kconfig > @@ -542,6 +542,7 @@ source "drivers/clk/starfive/Kconfig" > source "drivers/clk/sunxi/Kconfig" > source "drivers/clk/sunxi-ng/Kconfig" > source "drivers/clk/tegra/Kconfig" > +source "drivers/clk/tenstorrent/Kconfig" > source "drivers/clk/thead/Kconfig" > source "drivers/clk/stm32/Kconfig" > source "drivers/clk/ti/Kconfig" > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index 61ec08404442..f88c116d315f 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -156,6 +156,7 @@ obj-y += starfive/ > obj-$(CONFIG_ARCH_SUNXI) += sunxi/ > obj-y += sunxi-ng/ > obj-$(CONFIG_ARCH_TEGRA) += tegra/ > +obj-y += tenstorrent/ > obj-$(CONFIG_ARCH_THEAD) += thead/ > obj-y += ti/ > obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ > diff --git a/drivers/clk/tenstorrent/Kconfig b/drivers/clk/tenstorrent/Kconfig > new file mode 100644 > index 000000000000..9d4391eeeae0 > --- /dev/null > +++ b/drivers/clk/tenstorrent/Kconfig > @@ -0,0 +1,14 @@ > +# SPDX-License-Identifier: GPL-2.0-only > + > +config TENSTORRENT_ATLANTIS_PRCM > + tristate "Support for Tenstorrent Atlantis PRCM Clock Controller" > + depends on ARCH_TENSTORRENT || COMPILE_TEST > + default ARCH_TENSTORRENT > + select REGMAP_MMIO > + select AUXILIARY_BUS > + select MFD_SYSCON > + help > + Say yes here to support the different clock > + controllers found in the Tenstorrent Atlantis SoC. > + This includes the clocks from the RCPU, HSIO, MMIO > + and PCIE domain. > diff --git a/drivers/clk/tenstorrent/Makefile b/drivers/clk/tenstorrent/Makefile > new file mode 100644 > index 000000000000..95d87bac7bf5 > --- /dev/null > +++ b/drivers/clk/tenstorrent/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > +obj-$(CONFIG_TENSTORRENT_ATLANTIS_PRCM) += atlantis-prcm.o > diff --git a/drivers/clk/tenstorrent/atlantis-prcm.c b/drivers/clk/tenstorrent/atlantis-prcm.c > new file mode 100644 > index 000000000000..6bedb3e5ec7a > --- /dev/null > +++ b/drivers/clk/tenstorrent/atlantis-prcm.c > @@ -0,0 +1,901 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Tenstorrent Atlantis PRCM Clock Driver > + * > + * Copyright (c) 2026 Tenstorrent > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* RCPU Clock Register Offsets */ > +#define RCPU_PLL_CFG_REG 0x0000 > +#define RCPU_NOCC_PLL_CFG_REG 0x0004 > +#define RCPU_NOCC_CLK_CFG_REG 0x0008 > +#define RCPU_DIV_CFG_REG 0x000C > +#define RCPU_BLK_CG_REG 0x0014 > +#define LSIO_BLK_CG_REG 0x0018 > +#define PLL_RCPU_EN_REG 0x011c > +#define PLL_NOCC_EN_REG 0x0120 > +#define BUS_CG_REG 0x01FC > + > +/* PLL Bit Definitions */ > +#define PLL_CFG_EN_BIT BIT(0) > +#define PLL_CFG_BYPASS_BIT BIT(1) > +#define PLL_CFG_REFDIV_MASK GENMASK(7, 2) > +#define PLL_CFG_REFDIV_SHIFT 2 > +#define PLL_CFG_POSTDIV1_MASK GENMASK(10, 8) > +#define PLL_CFG_POSTDIV1_SHIFT 8 > +#define PLL_CFG_POSTDIV2_MASK GENMASK(13, 11) > +#define PLL_CFG_POSTDIV2_SHIFT 11 > +#define PLL_CFG_FBDIV_MASK GENMASK(25, 14) > +#define PLL_CFG_FBDIV_SHIFT 14 > +#define PLL_CFG_LKDT_BIT BIT(30) > +#define PLL_CFG_LOCK_BIT BIT(31) > +#define PLL_LOCK_TIMEOUT_US 1000 > +#define PLL_BYPASS_WAIT_US 500 > + > +struct atlantis_clk_common { > + int clkid; > + struct regmap *regmap; > + struct clk_hw hw; > +}; > + > +static inline struct atlantis_clk_common * > +hw_to_atlantis_clk_common(struct clk_hw *hw) > +{ > + return container_of(hw, struct atlantis_clk_common, hw); > +} > + > +struct atlantis_clk_mux_config { > + u8 shift; > + u8 width; > + u32 reg_offset; > +}; > + > +struct atlantis_clk_mux { > + struct atlantis_clk_common common; > + struct atlantis_clk_mux_config config; > +}; > + > +struct atlantis_clk_gate_config { > + u32 reg_offset; > + u32 enable; > +}; > + > +struct atlantis_clk_gate { > + struct atlantis_clk_common common; > + struct atlantis_clk_gate_config config; > +}; > + > +struct atlantis_clk_divider_config { > + u8 shift; > + u8 width; > + u32 flags; > + u32 reg_offset; > +}; > + > +struct atlantis_clk_divider { > + struct atlantis_clk_common common; > + struct atlantis_clk_divider_config config; > +}; > + > +struct atlantis_clk_pll_config { > + u32 tbl_num; > + u32 reg_offset; > + u32 en_reg_offset; > + u32 cg_reg_offset; > + u32 cg_reg_enable; > +}; > + > +/* Models a PLL with Bypass Functionality and Enable Bit + a Gate Clock at it's output */ > +struct atlantis_clk_pll { > + struct atlantis_clk_common common; > + struct atlantis_clk_pll_config config; > +}; > + > +struct atlantis_clk_gate_shared_config { > + u32 reg_offset; > + u32 enable; > + unsigned int *share_count; Why is this a pointer? Could this just be a plain unsigned int since all occurrences of this are dereferenced? > + spinlock_t *refcount_lock; > +}; > + > +struct atlantis_clk_gate_shared { > + struct atlantis_clk_common common; > + struct atlantis_clk_gate_shared_config config; > +}; > + > +struct atlantis_clk_fixed_factor_config { > + unsigned int mult; > + unsigned int div; > +}; > + > +struct atlantis_clk_fixed_factor { > + struct atlantis_clk_fixed_factor_config config; > + struct atlantis_clk_common common; > +}; > + > +static inline struct atlantis_clk_mux *hw_to_atlantis_clk_mux(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_mux, common); > +} > + > +static inline struct atlantis_clk_gate * > +hw_to_atlantis_clk_gate(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_gate, common); > +} > + > +static inline struct atlantis_clk_divider * > +hw_to_atlantis_clk_divider(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_divider, common); > +} > + > +static inline struct atlantis_clk_pll *hw_to_atlantis_pll(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_pll, common); > +} > + > +static inline struct atlantis_clk_gate_shared * > +hw_to_atlantis_clk_gate_shared(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_gate_shared, common); > +} > + > +static inline struct atlantis_clk_fixed_factor * > +hw_to_atlantis_clk_fixed_factor(struct clk_hw *hw) > +{ > + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); > + > + return container_of(common, struct atlantis_clk_fixed_factor, common); > +} > + > +static u8 atlantis_clk_mux_get_parent(struct clk_hw *hw) > +{ > + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); > + u32 val; > + > + regmap_read(mux->common.regmap, mux->config.reg_offset, &val); > + val >>= mux->config.shift; > + val &= (BIT(mux->config.width) - 1); > + > + return val; > +} > + > +static int atlantis_clk_mux_set_parent(struct clk_hw *hw, u8 index) > +{ > + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); > + u32 val = index; > + > + return regmap_update_bits(mux->common.regmap, mux->config.reg_offset, > + (BIT(mux->config.width) - 1) > + << mux->config.shift, > + val << mux->config.shift); > +} > + > +static int atlantis_clk_mux_determine_rate(struct clk_hw *hw, > + struct clk_rate_request *req) > +{ > + return clk_mux_determine_rate_flags(hw, req, hw->init->flags); > +} > + > +const struct clk_ops atlantis_clk_mux_ops = { > + .get_parent = atlantis_clk_mux_get_parent, > + .set_parent = atlantis_clk_mux_set_parent, > + .determine_rate = atlantis_clk_mux_determine_rate, > +}; static const > + > +static void atlantis_clk_gate_endisable(struct clk_hw *hw, int enable) > +{ > + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); > + u32 val; > + > + if (enable) > + val = gate->config.enable; > + else > + val = ~(gate->config.enable); > + > + regmap_update_bits(gate->common.regmap, gate->config.reg_offset, > + gate->config.enable, val); > +} > + > +static int atlantis_clk_gate_enable(struct clk_hw *hw) > +{ > + atlantis_clk_gate_endisable(hw, 1); > + > + return 0; > +} > + > +static void atlantis_clk_gate_disable(struct clk_hw *hw) > +{ > + atlantis_clk_gate_endisable(hw, 0); > +} > + > +static int atlantis_clk_gate_is_enabled(struct clk_hw *hw) > +{ > + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); > + u32 val; > + > + regmap_read(gate->common.regmap, gate->config.reg_offset, &val); > + > + val &= gate->config.enable; > + > + return val ? 1 : 0; What do you think about this instead? return !!val; > +} > + > +const struct clk_ops atlantis_clk_gate_ops = { > + .enable = atlantis_clk_gate_enable, > + .disable = atlantis_clk_gate_disable, > + .is_enabled = atlantis_clk_gate_is_enabled, > +}; static const > + > +static unsigned long atlantis_clk_divider_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct atlantis_clk_divider *divider = hw_to_atlantis_clk_divider(hw); > + u32 val; > + > + regmap_read(divider->common.regmap, divider->config.reg_offset, &val); > + > + val >>= divider->config.shift; > + val &= ((1 << (divider->config.width)) - 1); > + > + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); > +} > + > +const struct clk_ops atlantis_clk_divider_ops = { > + .recalc_rate = atlantis_clk_divider_recalc_rate, > +}; static const > + > +static unsigned long > +atlantis_clk_fixed_factor_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct atlantis_clk_fixed_factor *factor = > + hw_to_atlantis_clk_fixed_factor(hw); > + unsigned long long rate; > + > + rate = (unsigned long long)parent_rate * factor->config.mult; > + do_div(rate, factor->config.div); > + return (unsigned long)rate; > +} > + > +const struct clk_ops atlantis_clk_fixed_factor_ops = { > + .recalc_rate = atlantis_clk_fixed_factor_recalc_rate, > +}; static const > + > +static int atlantis_clk_pll_is_enabled(struct clk_hw *hw) > +{ > + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); > + u32 val, en_val, cg_val; > + > + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); > + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); > + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); > + > + /* Check if PLL is powered on, locked and Gate clk is enabled */ > + return !!(en_val & PLL_CFG_EN_BIT) && !!(val & PLL_CFG_LOCK_BIT) && > + !!(cg_val & pll->config.cg_reg_enable); > +} > + > +static int atlantis_clk_pll_enable(struct clk_hw *hw) > +{ > + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); > + u32 val, en_val, cg_val; > + int ret; > + > + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); > + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); > + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); > + > + /* Check if PLL is already enabled, locked and Gate clk is enabled */ > + if ((en_val & PLL_CFG_EN_BIT) && (val & PLL_CFG_LOCK_BIT) && > + (cg_val & pll->config.cg_reg_enable) && > + !(val & PLL_CFG_BYPASS_BIT)) { > + return 0; > + } > + > + /* Step 1: Set bypass mode first */ > + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, > + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); > + > + /* Step 2: Enable PLL (clear then set power bit) */ > + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, > + PLL_CFG_EN_BIT, 0); > + > + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, > + PLL_CFG_EN_BIT, PLL_CFG_EN_BIT); > + > + /* Step 3: Wait for PLL lock */ > + ret = regmap_read_poll_timeout(pll->common.regmap, > + pll->config.reg_offset, val, > + val & PLL_CFG_LOCK_BIT, 10, > + PLL_BYPASS_WAIT_US); > + if (ret) { > + pr_err("PLL failed to lock within timeout\n"); > + return ret; > + } > + > + /* Step 4: Switch from bypass to PLL output */ > + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, > + PLL_CFG_BYPASS_BIT, 0); > + > + /* Enable Gate clk at PLL Output */ > + return regmap_update_bits(pll->common.regmap, pll->config.cg_reg_offset, > + pll->config.cg_reg_enable, > + pll->config.cg_reg_enable); > +} > + > +static void atlantis_clk_pll_disable(struct clk_hw *hw) > +{ > + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); > + > + /* Step 1: Switch to bypass mode before disabling */ > + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, > + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); > + /* Step 2: Power down PLL */ > + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, > + PLL_CFG_EN_BIT, 0); > +} > + > +static unsigned long atlantis_clk_pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); > + > + u32 val, refdiv, fbdiv, postdiv1, postdiv2; > + u64 fout; > + > + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); > + > + if (val & PLL_CFG_BYPASS_BIT) > + return parent_rate; > + > + refdiv = FIELD_GET(PLL_CFG_REFDIV_MASK, val); > + fbdiv = FIELD_GET(PLL_CFG_FBDIV_MASK, val); > + postdiv1 = FIELD_GET(PLL_CFG_POSTDIV1_MASK, val); > + postdiv2 = FIELD_GET(PLL_CFG_POSTDIV2_MASK, val); > + > + if (!refdiv) > + refdiv = 1; > + if (!postdiv1) > + postdiv1 = 1; > + if (!postdiv2) > + postdiv2 = 1; > + if (!fbdiv) > + return 0; > + > + fout = div64_u64((u64)parent_rate * fbdiv, > + refdiv * postdiv1 * postdiv2); > + > + return fout; > +} > + > +const struct clk_ops atlantis_clk_pll_ops = { > + .enable = atlantis_clk_pll_enable, > + .disable = atlantis_clk_pll_disable, > + .recalc_rate = atlantis_clk_pll_recalc_rate, > + .is_enabled = atlantis_clk_pll_is_enabled, > +}; static const > + > +static int atlantis_clk_gate_shared_enable(struct clk_hw *hw) > +{ > + struct atlantis_clk_gate_shared *gate = > + hw_to_atlantis_clk_gate_shared(hw); > + bool need_enable; > + u32 reg; > + > + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) > + { > + need_enable = (*gate->config.share_count)++ == 0; > + if (need_enable) { > + regmap_read(gate->common.regmap, > + gate->config.reg_offset, ®); > + reg |= gate->config.enable; > + regmap_write(gate->common.regmap, > + gate->config.reg_offset, reg); > + } > + } > + > + if (need_enable) { > + regmap_read(gate->common.regmap, gate->config.reg_offset, ®); > + > + if (!(reg & gate->config.enable)) { > + pr_warn("%s: gate enable %d failed to enable\n", > + clk_hw_get_name(hw), gate->config.enable); > + return -EIO; > + } > + } Should this check be done within the scoped_guard? > + > + return 0; > +} > + > +static void atlantis_clk_gate_shared_disable(struct clk_hw *hw) > +{ > + struct atlantis_clk_gate_shared *gate = > + hw_to_atlantis_clk_gate_shared(hw); > + u32 reg; > + > + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) > + { > + if (WARN_ON(*gate->config.share_count == 0)) > + return; > + if (--(*gate->config.share_count) > 0) > + return; > + > + regmap_read(gate->common.regmap, gate->config.reg_offset, ®); > + reg &= ~gate->config.enable; > + regmap_write(gate->common.regmap, gate->config.reg_offset, reg); > + } > +} > + > +static int atlantis_clk_gate_shared_is_enabled(struct clk_hw *hw) > +{ > + struct atlantis_clk_gate_shared *gate = > + hw_to_atlantis_clk_gate_shared(hw); > + u32 reg; > + > + regmap_read(gate->common.regmap, gate->config.reg_offset, ®); > + > + return !!(reg & gate->config.enable); > +} > + > +static void atlantis_clk_gate_shared_disable_unused(struct clk_hw *hw) > +{ > + struct atlantis_clk_gate_shared *gate = > + hw_to_atlantis_clk_gate_shared(hw); > + > + u32 reg; > + > + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) > + { > + if (*gate->config.share_count == 0) { > + regmap_read(gate->common.regmap, > + gate->config.reg_offset, ®); > + reg &= ~gate->config.enable; > + regmap_write(gate->common.regmap, > + gate->config.reg_offset, reg); > + } > + } > +} > + > +const struct clk_ops atlantis_clk_gate_shared_ops = { > + .enable = atlantis_clk_gate_shared_enable, > + .disable = atlantis_clk_gate_shared_disable, > + .disable_unused = atlantis_clk_gate_shared_disable_unused, > + .is_enabled = atlantis_clk_gate_shared_is_enabled, > +}; static const > + > +#define ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, _cg_reg_offset, \ > + _cg_reg_enable) \ > + { \ > + .reg_offset = (_reg_offset), \ > + .en_reg_offset = (_en_reg_offset), \ > + .cg_reg_offset = (_cg_reg_offset), \ > + .cg_reg_enable = (_cg_reg_enable), \ > + } > + > +#define ATLANTIS_PLL_DEFINE(_clkid, _name, _parent, _reg_offset, \ > + _en_reg_offset, _cg_reg_offset, _cg_reg_enable, \ > + _flags) \ > + static struct atlantis_clk_pll _name = { \ > + .config = ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, \ > + _cg_reg_offset, _cg_reg_enable), \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ > + #_name, _parent, &atlantis_clk_pll_ops, \ > + _flags) }, \ > + } > +#define ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset) \ > + { \ > + .shift = _shift, .width = _width, .reg_offset = _reg_offset \ > + } > + > +#define ATLANTIS_MUX_DEFINE(_clkid, _name, _parents, _reg_offset, _shift, \ > + _width, _flags) \ > + static struct atlantis_clk_mux _name = { \ > + .config = ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset), \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ > + #_name, _parents, &atlantis_clk_mux_ops, \ > + _flags) } \ > + } > + > +#define ATLANTIS_DIVIDER_CONFIG(_shift, _width, _flags, _reg_offset) \ > + { \ > + .shift = _shift, .width = _width, .flags = _flags, \ > + .reg_offset = _reg_offset \ > + } > + > +#define ATLANTIS_DIVIDER_DEFINE(_clkid, _name, _parent, _reg_offset, _shift, \ > + _width, _divflags, _flags) \ > + static struct atlantis_clk_divider _name = { \ > + .config = ATLANTIS_DIVIDER_CONFIG(_shift, _width, _divflags, \ > + _reg_offset), \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_HW( \ > + #_name, &_parent.common.hw, \ > + &atlantis_clk_divider_ops, _flags) } \ > + } > +#define ATLANTIS_GATE_CONFIG(_enable, _reg_offset) \ > + { \ > + .enable = _enable, .reg_offset = _reg_offset \ > + } > + > +#define ATLANTIS_GATE_DEFINE(_clkid, _name, _parent, _reg_offset, _enable, \ > + _flags) \ > + static struct atlantis_clk_gate _name = { \ > + .config = ATLANTIS_GATE_CONFIG(_enable, _reg_offset), \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_HW( \ > + #_name, &_parent.common.hw, \ > + &atlantis_clk_gate_ops, _flags) } \ > + } > +#define ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, _share_count) \ > + { \ > + .reg_offset = _reg_offset, .enable = _enable, \ > + .share_count = _share_count, .refcount_lock = &refcount_lock \ > + } > +#define ATLANTIS_GATE_SHARED_DEFINE(_clkid, _name, _parent, _reg_offset, \ > + _enable, _share_count, _flags) \ > + static struct atlantis_clk_gate_shared _name = { \ > + .config = ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, \ > + _share_count), \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_HW( \ > + #_name, &_parent.common.hw, \ > + &atlantis_clk_gate_shared_ops, _flags) } \ > + } > +#define ATLANTIS_CLK_FIXED_FACTOR_DEFINE(_clkid, _name, _parent, _mult, _div, \ > + _flags) \ > + static struct atlantis_clk_fixed_factor _name = { \ > + .config = { .mult = _mult, .div = _div }, \ > + .common = { .clkid = _clkid, \ > + .hw.init = CLK_HW_INIT_HW( \ > + #_name, &_parent.common.hw, \ > + &atlantis_clk_fixed_factor_ops, _flags) } \ > + } > + > +static DEFINE_SPINLOCK(refcount_lock); /* Lock for refcount value accesses */ > + > +static const struct regmap_config atlantis_prcm_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > + .max_register = 0xFFFC, > + .cache_type = REGCACHE_NONE, > +}; > + > +struct atlantis_prcm_data { > + struct clk_hw **hws; > + size_t num; > + const char *reset_name; > +}; > + > +static const struct clk_parent_data osc_24m_clk[] = { > + { .index = 0 }, > +}; > + > +ATLANTIS_PLL_DEFINE(CLK_RCPU_PLL, rcpu_pll_clk, osc_24m_clk, RCPU_PLL_CFG_REG, > + PLL_RCPU_EN_REG, BUS_CG_REG, BIT(7), > + CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_UNGATE | > + CLK_IS_CRITICAL); > + > +static const struct clk_parent_data rcpu_root_parents[] = { > + { .index = 0 }, > + { .hw = &rcpu_pll_clk.common.hw }, > +}; > + > +ATLANTIS_MUX_DEFINE(CLK_RCPU_ROOT, rcpu_root_mux, rcpu_root_parents, > + RCPU_DIV_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT); > + > +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV2, rcpu_div2_clk, rcpu_root_mux, > + RCPU_DIV_CFG_REG, 2, 4, 0, 0); > +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV4, rcpu_div4_clk, rcpu_root_mux, > + RCPU_DIV_CFG_REG, 7, 4, 0, 0); > +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_RTC, rcpu_rtc_clk, rcpu_div4_clk, > + RCPU_DIV_CFG_REG, 12, 6, 0, 0); > + > +ATLANTIS_GATE_DEFINE(CLK_SMNDMA0_ACLK, smndma0_aclk, rcpu_div2_clk, > + RCPU_BLK_CG_REG, BIT(0), 0); > +ATLANTIS_GATE_DEFINE(CLK_SMNDMA1_ACLK, smndma1_aclk, rcpu_div2_clk, > + RCPU_BLK_CG_REG, BIT(1), 0); > +ATLANTIS_GATE_DEFINE(CLK_WDT0_PCLK, wdt0_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(2), 0); > +ATLANTIS_GATE_DEFINE(CLK_WDT1_PCLK, wdt1_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(3), 0); > +ATLANTIS_GATE_DEFINE(CLK_TIMER_PCLK, timer_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(4), 0); > +ATLANTIS_GATE_DEFINE(CLK_PVTC_PCLK, pvtc_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(12), 0); > +ATLANTIS_GATE_DEFINE(CLK_PMU_PCLK, pmu_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(13), 0); > +ATLANTIS_GATE_DEFINE(CLK_MAILBOX_HCLK, mb_hclk, rcpu_div2_clk, RCPU_BLK_CG_REG, > + BIT(14), 0); > +ATLANTIS_GATE_DEFINE(CLK_SEC_SPACC_HCLK, sec_spacc_hclk, rcpu_div2_clk, > + RCPU_BLK_CG_REG, BIT(26), 0); > +ATLANTIS_GATE_DEFINE(CLK_SEC_OTP_HCLK, sec_otp_hclk, rcpu_div2_clk, > + RCPU_BLK_CG_REG, BIT(28), 0); > +ATLANTIS_GATE_DEFINE(CLK_TRNG_PCLK, trng_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, > + BIT(29), 0); > +ATLANTIS_GATE_DEFINE(CLK_SEC_CRC_HCLK, sec_crc_hclk, rcpu_div2_clk, > + RCPU_BLK_CG_REG, BIT(30), 0); > + > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_SMN_HCLK, rcpu_smn_hclk, rcpu_div2_clk, 1, > + 1, 0); > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_AHB0_HCLK, rcpu_ahb0_hclk, rcpu_div2_clk, > + 1, 1, 0); > + > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_SMN_PCLK, rcpu_smn_pclk, rcpu_div4_clk, 1, > + 1, 0); > + > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_SMN_CLK, rcpu_smn_clk, rcpu_root_mux, 1, 1, > + 0); > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_SCRATCHPAD_CLK, rcpu_scratchpad_aclk, > + rcpu_root_mux, 1, 1, 0); > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_RCPU_CORE_CLK, rcpu_core_clk, > + rcpu_root_mux, 1, 1, 0); > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_RCPU_ROM_CLK, rcpu_rom_aclk, rcpu_root_mux, > + 1, 1, 0); > + > +static struct atlantis_clk_fixed_factor > + otp_load_clk = { .config = { .mult = 1, .div = 1 }, > + .common = { > + .clkid = CLK_OTP_LOAD_CLK, > + .hw.init = CLK_HW_INIT_PARENTS_DATA( > + "otp_load_clk", osc_24m_clk, > + &atlantis_clk_fixed_factor_ops, > + CLK_SET_RATE_NO_REPARENT), > + } }; > + > +ATLANTIS_PLL_DEFINE(CLK_NOC_PLL, nocc_pll_clk, osc_24m_clk, > + RCPU_NOCC_PLL_CFG_REG, PLL_NOCC_EN_REG, BUS_CG_REG, BIT(0), > + CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_UNGATE | > + CLK_IS_CRITICAL); > + > +static const struct clk_parent_data nocc_mux_parents[] = { > + { .index = 0 }, > + { .hw = &nocc_pll_clk.common.hw }, > +}; > + > +ATLANTIS_MUX_DEFINE(CLK_NOCC_CLK, nocc_clk_mux, nocc_mux_parents, > + RCPU_NOCC_CLK_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT); > + > +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV2, nocc_div2_clk, nocc_clk_mux, > + RCPU_NOCC_CLK_CFG_REG, 1, 4, 0, 0); > +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV4, nocc_div4_clk, nocc_clk_mux, > + RCPU_NOCC_CLK_CFG_REG, 5, 4, 0, 0); > +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_RTC, nocc_rtc_clk, nocc_div4_clk, > + RCPU_NOCC_CLK_CFG_REG, 9, 6, 0, 0); > +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_CAN, nocc_can_div, nocc_clk_mux, > + RCPU_NOCC_CLK_CFG_REG, 15, 4, 0, 0); > + > +static unsigned int refcnt_qspi; > +ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_SCLK, qspi_sclk, nocc_clk_mux, > + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); > +ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_HCLK, qspi_hclk, nocc_div2_clk, > + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); > +ATLANTIS_GATE_DEFINE(CLK_I2C0_PCLK, i2c0_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(1), 0); > +ATLANTIS_GATE_DEFINE(CLK_I2C1_PCLK, i2c1_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(2), 0); > +ATLANTIS_GATE_DEFINE(CLK_I2C2_PCLK, i2c2_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(3), 0); > +ATLANTIS_GATE_DEFINE(CLK_I2C3_PCLK, i2c3_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(4), 0); > +ATLANTIS_GATE_DEFINE(CLK_I2C4_PCLK, i2c4_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(5), 0); > + > +ATLANTIS_GATE_DEFINE(CLK_UART0_PCLK, uart0_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(6), 0); > +ATLANTIS_GATE_DEFINE(CLK_UART1_PCLK, uart1_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(7), 0); > +ATLANTIS_GATE_DEFINE(CLK_UART2_PCLK, uart2_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(8), 0); > +ATLANTIS_GATE_DEFINE(CLK_UART3_PCLK, uart3_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(9), 0); > +ATLANTIS_GATE_DEFINE(CLK_UART4_PCLK, uart4_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(10), 0); > +ATLANTIS_GATE_DEFINE(CLK_SPI0_PCLK, spi0_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(11), 0); > +ATLANTIS_GATE_DEFINE(CLK_SPI1_PCLK, spi1_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(12), 0); > +ATLANTIS_GATE_DEFINE(CLK_SPI2_PCLK, spi2_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(13), 0); > +ATLANTIS_GATE_DEFINE(CLK_SPI3_PCLK, spi3_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(14), 0); > +ATLANTIS_GATE_DEFINE(CLK_GPIO_PCLK, gpio_pclk, nocc_div4_clk, LSIO_BLK_CG_REG, > + BIT(15), 0); > + > +static unsigned int refcnt_can0; > +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_HCLK, can0_hclk, nocc_div2_clk, > + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); > +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_CLK, can0_clk, nocc_can_div, > + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); > + > +static unsigned int refcnt_can1; > +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_HCLK, can1_hclk, nocc_div2_clk, > + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); > +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_CLK, can1_clk, nocc_can_div, > + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); > + > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_CAN0_TIMER_CLK, can0_timer_clk, > + nocc_rtc_clk, 1, 1, 0); > +ATLANTIS_CLK_FIXED_FACTOR_DEFINE(CLK_CAN1_TIMER_CLK, can1_timer_clk, > + nocc_rtc_clk, 1, 1, 0); > + > +static struct clk_hw *atlantis_rcpu_clks[] = { > + [CLK_RCPU_PLL] = &rcpu_pll_clk.common.hw, > + [CLK_RCPU_ROOT] = &rcpu_root_mux.common.hw, > + [CLK_RCPU_DIV2] = &rcpu_div2_clk.common.hw, > + [CLK_RCPU_DIV4] = &rcpu_div4_clk.common.hw, > + [CLK_RCPU_RTC] = &rcpu_rtc_clk.common.hw, > + [CLK_SMNDMA0_ACLK] = &smndma0_aclk.common.hw, > + [CLK_SMNDMA1_ACLK] = &smndma1_aclk.common.hw, > + [CLK_WDT0_PCLK] = &wdt0_pclk.common.hw, > + [CLK_WDT1_PCLK] = &wdt1_pclk.common.hw, > + [CLK_TIMER_PCLK] = &timer_pclk.common.hw, > + [CLK_PVTC_PCLK] = &pvtc_pclk.common.hw, > + [CLK_PMU_PCLK] = &pmu_pclk.common.hw, > + [CLK_MAILBOX_HCLK] = &mb_hclk.common.hw, > + [CLK_SEC_SPACC_HCLK] = &sec_spacc_hclk.common.hw, > + [CLK_SEC_OTP_HCLK] = &sec_otp_hclk.common.hw, > + [CLK_TRNG_PCLK] = &trng_pclk.common.hw, > + [CLK_SEC_CRC_HCLK] = &sec_crc_hclk.common.hw, > + [CLK_SMN_HCLK] = &rcpu_smn_hclk.common.hw, > + [CLK_AHB0_HCLK] = &rcpu_ahb0_hclk.common.hw, > + [CLK_SMN_PCLK] = &rcpu_smn_pclk.common.hw, > + [CLK_SMN_CLK] = &rcpu_smn_clk.common.hw, > + [CLK_SCRATCHPAD_CLK] = &rcpu_scratchpad_aclk.common.hw, > + [CLK_RCPU_CORE_CLK] = &rcpu_core_clk.common.hw, > + [CLK_RCPU_ROM_CLK] = &rcpu_rom_aclk.common.hw, > + [CLK_OTP_LOAD_CLK] = &otp_load_clk.common.hw, > + [CLK_NOC_PLL] = &nocc_pll_clk.common.hw, > + [CLK_NOCC_CLK] = &nocc_clk_mux.common.hw, > + [CLK_NOCC_DIV2] = &nocc_div2_clk.common.hw, > + [CLK_NOCC_DIV4] = &nocc_div4_clk.common.hw, > + [CLK_NOCC_RTC] = &nocc_rtc_clk.common.hw, > + [CLK_NOCC_CAN] = &nocc_can_div.common.hw, > + [CLK_QSPI_SCLK] = &qspi_sclk.common.hw, > + [CLK_QSPI_HCLK] = &qspi_hclk.common.hw, > + [CLK_I2C0_PCLK] = &i2c0_pclk.common.hw, > + [CLK_I2C1_PCLK] = &i2c1_pclk.common.hw, > + [CLK_I2C2_PCLK] = &i2c2_pclk.common.hw, > + [CLK_I2C3_PCLK] = &i2c3_pclk.common.hw, > + [CLK_I2C4_PCLK] = &i2c4_pclk.common.hw, > + [CLK_UART0_PCLK] = &uart0_pclk.common.hw, > + [CLK_UART1_PCLK] = &uart1_pclk.common.hw, > + [CLK_UART2_PCLK] = &uart2_pclk.common.hw, > + [CLK_UART3_PCLK] = &uart3_pclk.common.hw, > + [CLK_UART4_PCLK] = &uart4_pclk.common.hw, > + [CLK_SPI0_PCLK] = &spi0_pclk.common.hw, > + [CLK_SPI1_PCLK] = &spi1_pclk.common.hw, > + [CLK_SPI2_PCLK] = &spi2_pclk.common.hw, > + [CLK_SPI3_PCLK] = &spi3_pclk.common.hw, > + [CLK_GPIO_PCLK] = &gpio_pclk.common.hw, > + [CLK_CAN0_HCLK] = &can0_hclk.common.hw, > + [CLK_CAN0_CLK] = &can0_clk.common.hw, > + [CLK_CAN1_HCLK] = &can1_hclk.common.hw, > + [CLK_CAN1_CLK] = &can1_clk.common.hw, > + [CLK_CAN0_TIMER_CLK] = &can0_timer_clk.common.hw, > + [CLK_CAN1_TIMER_CLK] = &can1_timer_clk.common.hw, > +}; > + > +static const struct atlantis_prcm_data atlantis_prcm_rcpu_data = { > + .hws = atlantis_rcpu_clks, > + .num = ARRAY_SIZE(atlantis_rcpu_clks), > + .reset_name = "rcpu-reset" > +}; > + > +static int atlantis_prcm_clocks_register(struct device *dev, > + struct regmap *regmap, > + const struct atlantis_prcm_data *data) > +{ > + struct clk_hw_onecell_data *clk_data; > + int i, ret; > + size_t num_clks = data->num; > + > + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num), > + GFP_KERNEL); > + if (!clk_data) > + return -ENOMEM; > + > + for (i = 0; i < data->num; i++) { > + struct clk_hw *hw = data->hws[i]; > + const char *name = hw->init->name; > + struct atlantis_clk_common *common = > + hw_to_atlantis_clk_common(hw); You can join these two lines into one and you'll be at 83 characters. checkpatch.pl now allows up to 100. > + common->regmap = regmap; > + > + ret = devm_clk_hw_register(dev, hw); > + > + if (ret) { > + dev_err(dev, "Cannot register clock %d - %s\n", i, > + name); This will be at 81 characters if the lines are joined. However, bigger question is if this message should be dropped entirely? If this condition occurs, an error is logged here, and a second message will be logged in atlantis_prcm_probe() below. > + return ret; > + } > + > + clk_data->hws[common->clkid] = hw; > + } > + > + clk_data->num = num_clks; > + > + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); > + if (ret) > + dev_err(dev, "failed to add clock hardware provider (%d)\n", > + ret); Should this message also be dropped as well? Brian