From nobody Mon Feb 9 13:57:27 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D7A911A7056; Thu, 15 Aug 2024 14:02:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723730522; cv=none; b=C+w9djN2Ks2FW9bsNuwvno2aHo/WnDF+0E3zJik4HqE2pE2UxsN+Dmlw7QVxboxJh+1OAUvzfG5T8NIWafdzvKtUi4ueSiRSNhgfuyG19BDZLO1W7l3WhnKfRDuKssFksNrRm0q9r9OyK+Uh3jxBJtNEk4JKgbtXXdzJJp6bPDI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723730522; c=relaxed/simple; bh=pX087AmU1PaUgpUD1h/mJcraFHVX9O0NaJswXItglDY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZEuWo3WLzDWH97A3vBJt47Hw+BN0MqBICuMOCZO84n22EOR1LYiw+sWLRp56i4HHQfIQHryL6DgUgnAGtR64cB8NG3z2278xdOUI66OFShaCTzyAadF0EK0709CjV5WrpzP2eodJaSpVJqbSeJlKIO/dzgfjM011e2cGfYVMFM4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J8MJAMoB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="J8MJAMoB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F2ACEC32786; Thu, 15 Aug 2024 14:02:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723730522; bh=pX087AmU1PaUgpUD1h/mJcraFHVX9O0NaJswXItglDY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=J8MJAMoB3RMbrKDcxeIEFBw++2H3qlyRoZHHOgEggMAb6a6Z0dFnUj9IFqjALz2lr EyDo9geBCnDUY0uFjDFEXyRcGH78ET4HmFPCn9Xt88wy3+Zd2uRQOoNmqLeIufyxIS 4MIwFCItiwszWadPVmDoerQsY9xoQJ0g63iDnd88tauiukFdCOI+xwgQVd0f49DQBW CcjkNgOhI4TS+xZW3dtBDpOsfoVvTwMIv6lF3kg5n5gRmy/I4WM0+uXEgjxDvbXj2b o4eWcU4ezx0vwDb7eWEfyOT2sGfak+5AmK/bh+57hobHBhW1Wh6hmqmfNMFCbx6bIT o6/UpiZtRVQ/Q== From: Conor Dooley To: devicetree@vger.kernel.org Cc: conor@kernel.org, Conor Dooley , Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , linux-kernel@vger.kernel.org Subject: [RFC PATCH 08/11] copy meson clk-regmap for now Date: Thu, 15 Aug 2024 15:01:11 +0100 Message-ID: <20240815-skirmish-violator-8ce24c596b9f@spud> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240815-shindig-bunny-fd42792d638a@spud> References: <20240815-shindig-bunny-fd42792d638a@spud> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10704; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=7foUgvrOx4wJS1971cQwv0FEaKkGIfX/0niGM57yiMo=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGn7uHR95+69zHXwuvi1Lzd/v2ZJt9m4r4yD/5w7R9ikH J3cH9P3dpSyMIhxMMiKKbIk3u5rkVr/x2WHc89bmDmsTCBDGLg4BWAiC/QZ/qfwLHLZsc3zY9TW jdsM14pF512ZF7mdSe3MQ+2S2oNiP6cw/E+XWsQj8KTfp8HTmdeeL/fxxLZFvmfv/9vS13+3Ltu jnwcA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Conor Dooley Signed-off-by: Conor Dooley --- drivers/clk/microchip/Makefile | 1 + drivers/clk/microchip/clk-regmap.c | 186 +++++++++++++++++++++++++++++ drivers/clk/microchip/clk-regmap.h | 137 +++++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 drivers/clk/microchip/clk-regmap.c create mode 100644 drivers/clk/microchip/clk-regmap.h diff --git a/drivers/clk/microchip/Makefile b/drivers/clk/microchip/Makefile index 13250e04e46c..6b463066c64e 100644 --- a/drivers/clk/microchip/Makefile +++ b/drivers/clk/microchip/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_COMMON_CLK_PIC32) +=3D clk-core.o obj-$(CONFIG_PIC32MZDA) +=3D clk-pic32mzda.o obj-$(CONFIG_MCHP_CLK_MPFS) +=3D clk-mpfs.o obj-$(CONFIG_MCHP_CLK_MPFS) +=3D clk-mpfs-ccc.o +obj-y +=3D clk-regmap.o diff --git a/drivers/clk/microchip/clk-regmap.c b/drivers/clk/microchip/clk= -regmap.c new file mode 100644 index 000000000000..ad116d24f700 --- /dev/null +++ b/drivers/clk/microchip/clk-regmap.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include "clk-regmap.h" + +static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_gate_data *gate =3D clk_get_regmap_gate_data(clk); + int set =3D gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + + set ^=3D enable; + + return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx), + set ? BIT(gate->bit_idx) : 0); +} + +static int clk_regmap_gate_enable(struct clk_hw *hw) +{ + return clk_regmap_gate_endisable(hw, 1); +} + +static void clk_regmap_gate_disable(struct clk_hw *hw) +{ + clk_regmap_gate_endisable(hw, 0); +} + +static int clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_gate_data *gate =3D clk_get_regmap_gate_data(clk); + unsigned int val; + + regmap_read(clk->map, gate->offset, &val); + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + val ^=3D BIT(gate->bit_idx); + + val &=3D BIT(gate->bit_idx); + + return val ? 1 : 0; +} + +const struct clk_ops clk_regmap_gate_ops =3D { + .enable =3D clk_regmap_gate_enable, + .disable =3D clk_regmap_gate_disable, + .is_enabled =3D clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_regmap_gate_ops); + +const struct clk_ops clk_regmap_gate_ro_ops =3D { + .is_enabled =3D clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops); + +static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_div_data *div =3D clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret =3D regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>=3D div->shift; + val &=3D clk_div_mask(div->width); + return divider_recalc_rate(hw, prate, val, div->table, div->flags, + div->width); +} + +static int clk_regmap_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_div_data *div =3D clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + /* if read only, just return current value */ + if (div->flags & CLK_DIVIDER_READ_ONLY) { + ret =3D regmap_read(clk->map, div->offset, &val); + if (ret) + return ret; + + val >>=3D div->shift; + val &=3D clk_div_mask(div->width); + + return divider_ro_determine_rate(hw, req, div->table, + div->width, div->flags, val); + } + + return divider_determine_rate(hw, req, div->table, div->width, + div->flags); +} + +static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_div_data *div =3D clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret =3D divider_get_val(rate, parent_rate, div->table, div->width, + div->flags); + if (ret < 0) + return ret; + + val =3D (unsigned int)ret << div->shift; + return regmap_update_bits(clk->map, div->offset, + clk_div_mask(div->width) << div->shift, val); +}; + +/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ + +const struct clk_ops clk_regmap_divider_ops =3D { + .recalc_rate =3D clk_regmap_div_recalc_rate, + .determine_rate =3D clk_regmap_div_determine_rate, + .set_rate =3D clk_regmap_div_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); + +const struct clk_ops clk_regmap_divider_ro_ops =3D { + .recalc_rate =3D clk_regmap_div_recalc_rate, + .determine_rate =3D clk_regmap_div_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); + +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_mux_data *mux =3D clk_get_regmap_mux_data(clk); + unsigned int val; + int ret; + + ret =3D regmap_read(clk->map, mux->offset, &val); + if (ret) + return ret; + + val >>=3D mux->shift; + val &=3D mux->mask; + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_mux_data *mux =3D clk_get_regmap_mux_data(clk); + unsigned int val =3D clk_mux_index_to_val(mux->table, mux->flags, index); + + return regmap_update_bits(clk->map, mux->offset, + mux->mask << mux->shift, + val << mux->shift); +} + +static int clk_regmap_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk =3D to_clk_regmap(hw); + struct clk_regmap_mux_data *mux =3D clk_get_regmap_mux_data(clk); + + return clk_mux_determine_rate_flags(hw, req, mux->flags); +} + +const struct clk_ops clk_regmap_mux_ops =3D { + .get_parent =3D clk_regmap_mux_get_parent, + .set_parent =3D clk_regmap_mux_set_parent, + .determine_rate =3D clk_regmap_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); + +const struct clk_ops clk_regmap_mux_ro_ops =3D { + .get_parent =3D clk_regmap_mux_get_parent, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); + +MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/microchip/clk-regmap.h b/drivers/clk/microchip/clk= -regmap.h new file mode 100644 index 000000000000..e365312da54e --- /dev/null +++ b/drivers/clk/microchip/clk-regmap.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __CLK_REGMAP_H +#define __CLK_REGMAP_H + +#include +#include + +/** + * struct clk_regmap - regmap backed clock + * + * @hw: handle between common and hardware-specific interfaces + * @map: pointer to the regmap structure controlling the clock + * @data: data specific to the clock type + * + * Clock which is controlled by regmap backed registers. The actual type of + * of the clock is controlled by the clock_ops and data. + */ +struct clk_regmap { + struct clk_hw hw; + struct regmap *map; + void *data; +}; + +static inline struct clk_regmap *to_clk_regmap(struct clk_hw *hw) +{ + return container_of(hw, struct clk_regmap, hw); +} + +/** + * struct clk_regmap_gate_data - regmap backed gate specific data + * + * @offset: offset of the register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored + */ +struct clk_regmap_gate_data { + unsigned int offset; + u8 bit_idx; + u8 flags; +}; + +static inline struct clk_regmap_gate_data * +clk_get_regmap_gate_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_gate_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_gate_ops; +extern const struct clk_ops clk_regmap_gate_ro_ops; + +/** + * struct clk_regmap_div_data - regmap backed adjustable divider specific = data + * + * @offset: offset of the register controlling the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @table: array of value/divider pairs, last entry should have div =3D 0 + * + * Flags: + * Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored + */ +struct clk_regmap_div_data { + unsigned int offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; +}; + +static inline struct clk_regmap_div_data * +clk_get_regmap_div_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_div_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_divider_ops; +extern const struct clk_ops clk_regmap_divider_ro_ops; + +/** + * struct clk_regmap_mux_data - regmap backed multiplexer clock specific d= ata + * + * @hw: handle between common and hardware-specific interfaces + * @offset: offset of theregister controlling multiplexer + * @table: array of parent indexed register values + * @shift: shift to multiplexer bit field + * @mask: mask of mutliplexer bit field + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_divider except CLK_MUX_HIWORD_MASK which is ignored + */ +struct clk_regmap_mux_data { + unsigned int offset; + u32 *table; + u32 mask; + u8 shift; + u8 flags; +}; + +static inline struct clk_regmap_mux_data * +clk_get_regmap_mux_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_mux_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_mux_ops; +extern const struct clk_ops clk_regmap_mux_ro_ops; + +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ +struct clk_regmap _name =3D { \ + .data =3D &(struct clk_regmap_gate_data){ \ + .offset =3D (_reg), \ + .bit_idx =3D (_bit), \ + }, \ + .hw.init =3D &(struct clk_init_data) { \ + .name =3D #_name, \ + .ops =3D _ops, \ + .parent_hws =3D (const struct clk_hw *[]) { _pname }, \ + .num_parents =3D 1, \ + .flags =3D (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ +} + +#define MESON_PCLK(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) + +#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) +#endif /* __CLK_REGMAP_H */ --=20 2.43.0