* Re: [PATCH 00/43] ep93xx device tree conversion
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
@ 2023-04-24 11:31 ` Arnd Bergmann
[not found] ` <20230424152933.48b2ede1@kernel.org>
2023-04-24 12:34 ` [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx Nikita Shubin
` (6 subsequent siblings)
7 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2023-04-24 11:31 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S . Miller, Jonathan Neuschäfer, Russell King,
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Bartosz Golaszewski,
Brian Norris, Chuanhong Guo, Conor.Dooley, Damien Le Moal,
Daniel Lezcano, Dmitry Torokhov, Emil Renner Berthing,
Eric Dumazet, Florian Fainelli, Guenter Roeck, Hartley Sweeten,
Heiko Stübner, Hitomi Hasegawa, Jakub Kicinski,
Jaroslav Kysela, Jean Delvare, Joel Stanley, Jonathan Cameron,
Krzysztof Kozlowski, Damien Le Moal, Liam Girdwood, Liang Yang,
Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, open list:GPIO SUBSYSTEM, linux-ide,
linux-input, linux-kernel, linux-mtd, linux-pm, linux-pwm,
linux-rtc, linux-spi, linux-watchdog, Netdev, soc
On Mon, Apr 24, 2023, at 14:34, Nikita Shubin wrote:
> This series aims to convert ep93xx from platform to full device tree support.
>
> Tested on ts7250 64 RAM/128 MiB Nand flash, edb9302.
>
> Thank you Linus and Arnd for your support, review and comments, sorry
> if i missed something -
> these series are quite big for me.
>
> Big thanks to Alexander Sverdlin for his testing, support, review,
> fixes and patches.
Thanks a lot for your continued work. I can't merge any of this at
the moment since the upstream merge window just opened, but I'm
happy to take this all through the soc tree for 6.5, provided we
get the sufficient Acks from the subsystem maintainers. Merging
it through each individual tree would take a lot longer, so I
hope we can avoid that.
Arnd
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
@ 2023-04-24 12:01 ` Christophe JAILLET
2023-04-24 17:17 ` kernel test robot
2023-04-29 0:58 ` Stephen Boyd
2 siblings, 0 replies; 26+ messages in thread
From: Christophe JAILLET @ 2023-04-24 12:01 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, Stephen Boyd, linux-kernel, linux-clk
Le 24/04/2023 à 14:34, Nikita Shubin a écrit :
> This is a rewrite of EP93xx timer driver in
> arch/arm/mach-ep93xx/clock.c trying to do everything
> the device tree way:
>
> - convert to syscon driver
> - provide clock acces via of
>
> Co-developed-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
>
> Notes:
> rfc->v0
> Linus Walleij:
> - renamed all __underscore
>
> Alexander Sverdlin:
> - "Logick" -> "Logic"
>
> Changes by Alexander Sverdlin:
> - remove pr_info
> - DIV_ROUND_UP_ULL -> DIV_ROUND_CLOSEST
> - fix zeroing bitfield in ep93xx_div_set_rate
> - add sanity check for EP93XX_SYSCON_CHIPID_ID
> - use bit index for DMA clock's
> - ep93xx_clk_register_gate() takes bit index, not mask
> - remove redundant define
> - use DIV_ROUND_CLOSEST() everywhere to achieve frequencies closer to those
> requested
> - Add the forgotten configuration from the deleted
> arch/arm/mach-ep93xx/core.c
>
> drivers/clk/Kconfig | 8 +
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-ep93xx.c | 880 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 889 insertions(+)
> create mode 100644 drivers/clk/clk-ep93xx.c
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 1eef05bb1f99..d3ad975b688e 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -436,6 +436,14 @@ config COMMON_CLK_K210
> help
> Support for the Canaan Kendryte K210 RISC-V SoC clocks.
>
> +config COMMON_CLK_EP93XX
> + bool "Clock driver for Cirrus Logic ep93xx SoC"
> + depends on ARCH_EP93XX || COMPILE_TEST
> + select MFD_SYSCON
> + select REGMAP
> + help
> + This driver supports the SoC clocks on the Cirrus Logic ep93xx.
> +
> source "drivers/clk/actions/Kconfig"
> source "drivers/clk/analogbits/Kconfig"
> source "drivers/clk/baikal-t1/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index e3ca0d058a25..deec25ffd004 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
> obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
> obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
> obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
> +obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
> obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
> obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
> obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
> diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c
> new file mode 100644
> index 000000000000..e5913fc4c39b
> --- /dev/null
> +++ b/drivers/clk/clk-ep93xx.c
> @@ -0,0 +1,880 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Clock control for Cirrus EP93xx chips.
> + * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
> + *
> + * Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
> + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
> + */
> +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/soc/cirrus/ep93xx.h>
> +#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
> +
> +#include <asm/div64.h>
> +
> +#define EP93XX_EXT_CLK_RATE 14745600
> +#define EP93XX_EXT_RTC_RATE 32768
> +
> +#define EP93XX_SYSCON_POWER_STATE 0x00
> +#define EP93XX_SYSCON_PWRCNT 0x04
> +#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
> +#define EP93XX_SYSCON_PWRCNT_USH_EN 28
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
> +#define EP93XX_SYSCON_CLKSET1 0x20
> +#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
> +#define EP93XX_SYSCON_CLKSET2 0x24
> +#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
> +#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
> +#define EP93XX_SYSCON_DEVCFG 0x80
> +#define EP93XX_SYSCON_DEVCFG_U3EN 24
> +#define EP93XX_SYSCON_DEVCFG_U2EN 20
> +#define EP93XX_SYSCON_DEVCFG_U1EN 18
> +#define EP93XX_SYSCON_VIDCLKDIV 0x84
> +#define EP93XX_SYSCON_CLKDIV_ENABLE 15
> +#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
> +#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
> +#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
> +#define EP93XX_SYSCON_I2SCLKDIV 0x8c
> +#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
> +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
> +#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
> +#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
> +#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
> +#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
> +#define EP93XX_SYSCON_CHIPID 0x94
> +#define EP93XX_SYSCON_CHIPID_ID 0x9213
> +
> +static DEFINE_SPINLOCK(clk_lock);
> +static struct regmap *ep93xx_map;
> +#define ep93xx_regmap_read(reg, val) regmap_read(ep93xx_map, reg, val)
> +
> +/* Keeps track of all clocks */
> +static struct clk_hw_onecell_data *ep93xx_clk_data;
> +
> +static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
> +static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
> +static char pclk_divisors[] = { 1, 2, 4, 8 };
> +
> +static char adc_divisors[] = { 16, 4 };
> +static char sclk_divisors[] = { 2, 4 };
> +static char lrclk_divisors[] = { 32, 64, 128 };
> +
> +static const char * const mux_parents[] = {
> + "xtali",
> + "pll1",
> + "pll2"
> +};
> +
> +/*
> + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
> + */
> +static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word)
> +{
> + int i;
> +
> + rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
> + rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
> + do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
> + for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
> + rate >>= 1;
> +
> + return (unsigned long)rate;
> +}
> +
> +struct clk_psc {
> + struct clk_hw hw;
> + unsigned int reg;
> + u8 bit_idx;
> + u32 mask;
> + u8 shift;
> + u8 width;
> + char *div;
> + u8 num_div;
> + spinlock_t *lock;
> +};
> +
> +#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
> +
> +static int ep93xx_clk_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> +
> + return (val & BIT(psc->bit_idx)) ? 1 : 0;
> +}
> +
> +static int ep93xx_clk_enable(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val |= BIT(psc->bit_idx);
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +
> + return 0;
> +}
> +
> +static void ep93xx_clk_disable(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~BIT(psc->bit_idx);
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +}
> +
> +static const struct clk_ops clk_ep93xx_gate_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> +};
> +
> +static struct clk_hw *ep93xx_clk_register_gate(const char *name,
> + const char *parent_name,
> + unsigned int reg,
> + u8 bit_idx)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &clk_ep93xx_gate_ops;
> + init.flags = CLK_SET_RATE_PARENT;
> + init.parent_names = (parent_name ? &parent_name : NULL);
> + init.num_parents = (parent_name ? 1 : 0);
> +
> + psc->reg = reg;
> + psc->bit_idx = bit_idx;
> + psc->hw.init = &init;
> + psc->lock = &clk_lock;
> +
> + clk = clk_register(NULL, &psc->hw);
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
> + return 0;
> +
> + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
> + return 1;
> +
> + return 2;
> +}
> +
> +static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (index >= ARRAY_SIZE(mux_parents))
> + return -EINVAL;
> +
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
> +
> + if (index != 0) {
> + val |= EP93XX_SYSCON_CLKDIV_ESEL;
> + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
> + }
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +
> + return 0;
> +}
> +
> +static bool is_best(unsigned long rate, unsigned long now,
> + unsigned long best)
> +{
> + return abs(rate - now) < abs(rate - best);
> +}
> +
> +static int ep93xx_mux_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + unsigned long rate = req->rate;
> + struct clk *parent_best = NULL;
> + unsigned long parent_rate;
> + unsigned long best_rate = 0, actual_rate, mclk_rate;
> + unsigned long parent_rate_best;
> + int div, pdiv;
> + int i;
> +
> + /*
> + * Try the two pll's and the external clock
> + * Because the valid predividers are 2, 2.5 and 3, we multiply
> + * all the clocks by 2 to avoid floating point math.
> + *
> + * This is based on the algorithm in the ep93xx raster guide:
> + * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
> + *
> + */
> + for (i = 0; i < ARRAY_SIZE(mux_parents); i++) {
> + struct clk *parent = clk_get_sys(mux_parents[i], NULL);
> +
> + parent_rate = clk_get_rate(parent);
> + mclk_rate = parent_rate * 2;
> +
> + /* Try each predivider value */
> + for (pdiv = 4; pdiv <= 6; pdiv++) {
> + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> + if (div < 1 || div > 127)
> + continue;
> +
> + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
> +
> + if (is_best(rate, actual_rate, best_rate)) {
> + best_rate = actual_rate;
> + parent_rate_best = parent_rate;
> + parent_best = parent;
> + }
> + }
> + }
> +
> + if (!parent_best)
> + return -EINVAL;
> +
> + req->best_parent_rate = parent_rate_best;
> + req->best_parent_hw = __clk_get_hw(parent_best);
> + req->rate = best_rate;
> +
> + return 0;
> +}
> +
> +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long rate = 0;
> + u32 val;
> + int pdiv, div;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
> + div = val & 0x7f;
> + if (div > 0)
> + rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
> +
> + return rate;
> +}
> +
> +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + int pdiv, div, npdiv, ndiv;
> + unsigned long actual_rate, mclk_rate, rate_err = -1;
> + int found = 0;
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + mclk_rate = parent_rate * 2;
> +
> + for (pdiv = 4; pdiv <= 6; pdiv++) {
> + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> + if (div < 1 || div > 127)
> + continue;
> +
> + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
> +
> + if (!found || abs(actual_rate - rate) < rate_err) {
> + npdiv = pdiv - 3;
> + ndiv = div;
> + rate_err = abs(actual_rate - rate);
> + found = 1;
> + }
> + }
> +
> + if (!found)
> + return -EINVAL;
> +
> + /* Clear old dividers */
> + val &= ~0x37f;
> +
> + /* Set the new pdiv and div bits for the new clock rate */
> + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops clk_ddiv_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> + .get_parent = ep93xx_mux_get_parent,
> + .set_parent = ep93xx_mux_set_parent_lock,
> + .determine_rate = ep93xx_mux_determine_rate,
> + .recalc_rate = ep93xx_ddiv_recalc_rate,
> + .set_rate = ep93xx_ddiv_set_rate,
> +};
> +
> +static struct clk_hw *clk_hw_register_ddiv(const char *name,
> + unsigned int reg,
> + u8 bit_idx)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &clk_ddiv_ops;
> + init.flags = 0;
> + init.parent_names = mux_parents;
> + init.num_parents = ARRAY_SIZE(mux_parents);
> +
> + psc->reg = reg;
> + psc->bit_idx = bit_idx;
> + psc->lock = &clk_lock;
> + psc->hw.init = &init;
> +
> + clk = clk_register(NULL, &psc->hw);
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> + u8 index;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + index = (val & psc->mask) >> psc->shift;
> + if (index > psc->num_div)
> + return 0;
> +
> + return DIV_ROUND_CLOSEST(parent_rate, psc->div[index]);
> +}
> +
> +static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long best = 0, now;
> + bool assigned = false;
> + int i;
> +
> + for (i = 0; i < psc->num_div; i++) {
> + if ((rate * psc->div[i]) == *parent_rate)
> + return rate;
> +
> + now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
> +
> + if (!assigned || is_best(rate, now, best))
> + best = now;
> + assigned = true;
> + }
> +
> + return best;
> +}
> +
> +static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> + int i;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~psc->mask;
> + for (i = 0; i < psc->num_div; i++)
> + if (rate == DIV_ROUND_CLOSEST(parent_rate, psc->div[i])) {
> + val |= i << psc->shift;
> + break;
> + }
> +
> + if (i == psc->num_div)
> + return -EINVAL;
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops ep93xx_div_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> + .recalc_rate = ep93xx_div_recalc_rate,
> + .round_rate = ep93xx_div_round_rate,
> + .set_rate = ep93xx_div_set_rate,
> +};
> +
> +static struct clk_hw *clk_hw_register_div(const char *name,
> + const char *parent_name,
> + unsigned int reg,
> + u8 enable_bit,
> + u8 shift,
> + u8 width,
> + char *clk_divisors,
> + u8 num_div)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &ep93xx_div_ops;
> + init.flags = 0;
> + init.parent_names = (parent_name ? &parent_name : NULL);
> + init.num_parents = 1;
> +
> + psc->reg = reg;
> + psc->bit_idx = enable_bit;
> + psc->mask = GENMASK(shift + width - 1, shift);
> + psc->shift = shift;
> + psc->div = clk_divisors;
> + psc->num_div = num_div;
> + psc->lock = &clk_lock;
> + psc->hw.init = &init;
> +
> + clk = clk_register(NULL, &psc->hw);
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +struct ep93xx_gate {
> + unsigned int idx;
> + unsigned int bit;
> + const char *dev_id;
> + const char *con_id;
> +};
> +
> +static struct ep93xx_gate ep93xx_uarts[] = {
> + {EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL},
> + {EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL},
> + {EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL},
> +};
> +
> +static void ep93xx_uart_clock_init(void)
> +{
> + unsigned int i;
> + struct clk_hw *hw;
> + u32 val;
> + unsigned int clk_uart_div;
> +
> + ep93xx_regmap_read(EP93XX_SYSCON_PWRCNT, &val);
> + if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
> + clk_uart_div = 1;
> + else
> + clk_uart_div = 2;
> +
> + hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div);
> + ep93xx_clk_data->hws[EP93XX_CLK_UART] = hw;
> +
> + /* parenting uart gate clocks to uart clock */
> + for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
> + hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id,
> + "uart",
> + EP93XX_SYSCON_DEVCFG,
> + ep93xx_uarts[i].bit);
> +
> + ep93xx_clk_data->hws[ep93xx_uarts[i].idx] = hw;
> + }
> +}
> +
> +static struct ep93xx_gate ep93xx_dmas[] = {
> + {EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"},
> + {EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"},
> + {EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"},
> + {EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"},
> + {EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"},
> + {EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"},
> + {EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"},
> + {EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"},
> + {EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"},
> + {EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"},
> + {EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"},
> + {EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"},
> +};
> +
> +static void ep93xx_dma_clock_init(void __iomem *base)
> +{
> + int i;
> + struct clk_hw *hw;
> + int ret;
> +
> + for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
> + hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id,
> + "hclk", 0,
> + base + EP93XX_SYSCON_PWRCNT,
> + ep93xx_dmas[i].bit,
> + 0,
> + &clk_lock);
> +
> + ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL);
> + if (ret) {
> + pr_err("%s: failed to register lookup %s\n",
> + __func__, ep93xx_dmas[i].con_id);
> + continue;
> + }
> +
> + ep93xx_clk_data->hws[ep93xx_dmas[i].idx] = hw;
> + }
> +}
> +
> +static int ep93xx_clk_probe(struct platform_device *pdev)
> +{
> + void __iomem *base;
> + unsigned int clk_usb_div;
> + unsigned long clk_spi_div;
> + struct clk_hw *hw;
> + struct device *dev = &pdev->dev;
> + u32 value;
> + struct resource *res;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> + clk_usb_div = (((value >> 28) & 0xf) + 1);
> + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
> + hw = clk_hw_register_gate(NULL, "ohci-platform",
> + "usb_clk", 0,
> + base + EP93XX_SYSCON_PWRCNT,
> + EP93XX_SYSCON_PWRCNT_USH_EN,
> + 0,
> + &clk_lock);
> + clk_hw_register_clkdev(hw, NULL, "ohci-platform");
> + ep93xx_clk_data->hws[EP93XX_CLK_USB] = hw;
> +
> + /*
> + * EP93xx SSP clock rate was doubled in version E2. For more information
> + * see:
> + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> + */
> + clk_spi_div = 1;
> + if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> + clk_spi_div = 2;
> + hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div);
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0");
> + ep93xx_clk_data->hws[EP93XX_CLK_SPI] = hw;
> +
> + /* pwm clock */
> + hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1);
> + clk_hw_register_clkdev(hw, "pwm_clk", NULL);
> + ep93xx_clk_data->hws[EP93XX_CLK_PWM] = hw;
> +
> + ep93xx_uart_clock_init();
> +
> + /* touchscreen/adc clock */
> + hw = clk_hw_register_div("ep93xx-adc",
> + "xtali",
> + EP93XX_SYSCON_KEYTCHCLKDIV,
> + EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
> + EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
> + 1,
> + adc_divisors,
> + ARRAY_SIZE(adc_divisors));
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-adc");
> + ep93xx_clk_data->hws[EP93XX_CLK_ADC] = hw;
> +
> + /* keypad clock */
> + hw = clk_hw_register_div("ep93xx-keypad",
> + "xtali",
> + EP93XX_SYSCON_KEYTCHCLKDIV,
> + EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
> + EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
> + 1,
> + adc_divisors,
> + ARRAY_SIZE(adc_divisors));
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad");
> + ep93xx_clk_data->hws[EP93XX_CLK_KEYPAD] = hw;
> +
> + /* On reset PDIV and VDIV is set to zero, while PDIV zero
> + * means clock disable, VDIV shouldn't be zero.
> + * So i set both dividers to minimum.
> + */
> + /* ENA - Enable CLK divider. */
> + /* PDIV - 00 - Disable clock */
> + /* VDIV - at least 2 */
> + /* Check and enable video clk registers */
> + ep93xx_regmap_read(EP93XX_SYSCON_VIDCLKDIV, &value);
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV);
> +
> + /* check and enable i2s clk registers */
> + ep93xx_regmap_read(EP93XX_SYSCON_I2SCLKDIV, &value);
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> + /*
> + * Override the SAI_MSTR_CLK_CFG from the I2S block and use the
> + * I2SClkDiv Register settings. LRCLK transitions on the falling SCLK
> + * edge.
> + */
> + value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
> + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV);
> +
> + /* video clk */
> + hw = clk_hw_register_ddiv("ep93xx-fb",
> + EP93XX_SYSCON_VIDCLKDIV,
> + EP93XX_SYSCON_CLKDIV_ENABLE);
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-fb");
> + ep93xx_clk_data->hws[EP93XX_CLK_VIDEO] = hw;
> +
> + /* i2s clk */
> + hw = clk_hw_register_ddiv("mclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_CLKDIV_ENABLE);
> +
> + clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_MCLK] = hw;
> +
> + /* i2s sclk */
> +#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16
> +#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1
> + hw = clk_hw_register_div("sclk",
> + "mclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_I2SCLKDIV_SENA,
> + EP93XX_I2SCLKDIV_SDIV_SHIFT,
> + EP93XX_I2SCLKDIV_SDIV_WIDTH,
> + sclk_divisors,
> + ARRAY_SIZE(sclk_divisors));
> +
> + clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_SCLK] = hw;
> +
> + /* i2s lrclk */
> +#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17
> +#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 2
> + hw = clk_hw_register_div("lrclk",
> + "sclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_I2SCLKDIV_SENA,
> + EP93XX_I2SCLKDIV_LRDIV32_SHIFT,
> + EP93XX_I2SCLKDIV_LRDIV32_WIDTH,
> + lrclk_divisors,
> + ARRAY_SIZE(lrclk_divisors));
> +
> + clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_LRCLK] = hw;
> +
> + /* IrDa clk uses same pattern but no init code presents in original clock driver */
> + return 0;
> +}
> +
> +static const struct of_device_id ep93xx_clk_dt_ids[] = {
> + { .compatible = "cirrus,ep9301-syscon", },
> + { /* sentinel */ },
> +};
> +
> +static struct platform_driver ep93xx_clk_driver = {
> + .probe = ep93xx_clk_probe,
> + .driver = {
> + .name = "ep93xx-clk",
> + .of_match_table = ep93xx_clk_dt_ids,
> + .suppress_bind_attrs = true,
> + },
> +};
> +builtin_platform_driver(ep93xx_clk_driver);
> +
> +static void __init ep93xx_clock_init(struct device_node *np)
> +{
> + void __iomem *base;
> + int i;
> + int ret;
> + u32 value;
> + struct clk_hw *hw;
> + unsigned long clk_pll1_rate;
> + unsigned long clk_f_rate;
> + unsigned long clk_h_rate;
> + unsigned long clk_p_rate;
> + unsigned long clk_pll2_rate;
> + unsigned int clk_f_div;
> + unsigned int clk_h_div;
> + unsigned int clk_p_div;
> +
> + ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
> + EP93XX_NUM_CLKS),
> + GFP_KERNEL);
> +
Hi,
This is never released if an error occures below.
Missing error handling or it is useless to care about it?
> + if (!ep93xx_clk_data)
> + return;
> +
> + /*
> + * This way all clock fetched before the platform device probes,
> + * except those we assign here for early use, will be deferred.
> + */
> + for (i = 0; i < EP93XX_NUM_CLKS; i++)
> + ep93xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
> +
> + base = of_iomap(np, 0);
Same.
> + /* Remap the system controller for the exclusive register */
> + if (IS_ERR(base)) {
> + pr_err("failed to map base\n");
> + return;
> + }
> +
> + ep93xx_map = syscon_node_to_regmap(np);
> + if (IS_ERR(ep93xx_map)) {
> + pr_err("no syscon regmap\n");
> + return;
> + }
> +
> + /*
> + * We check that the regmap works on this very first access,
> + * but as this is an MMIO-backed regmap, subsequent regmap
> + * access is not going to fail and we skip error checks from
> + * this point.
> + */
> + ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
> + if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
> + pr_err("failed to read global status register\n");
> + return;
> + }
> +
> + hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE);
> + clk_hw_register_clkdev(hw, NULL, "xtali");
> +
> + /* Determine the bootloader configured pll1 rate */
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET1, &value);
> + if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
> + clk_pll1_rate = EP93XX_EXT_CLK_RATE;
> + else
> + clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
> +
> + hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate);
> + clk_hw_register_clkdev(hw, NULL, "pll1");
> + ep93xx_clk_data->hws[EP93XX_CLK_PLL1] = hw;
> +
> + /* Initialize the pll1 derived clocks */
> + clk_f_div = fclk_divisors[(value >> 25) & 0x7];
> + clk_h_div = hclk_divisors[(value >> 20) & 0x7];
> + clk_p_div = pclk_divisors[(value >> 18) & 0x3];
> +
> + hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div);
> + clk_f_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_FCLK] = hw;
> + hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div);
> + clk_h_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_HCLK] = hw;
> + hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div);
> + clk_p_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_PCLK] = hw;
> +
> + clk_hw_register_clkdev(hw, "apb_pclk", NULL);
> +
> + ep93xx_dma_clock_init(base);
> +
> + /* Determine the bootloader configured pll2 rate */
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
> + clk_pll2_rate = EP93XX_EXT_CLK_RATE;
> + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
> + clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
> + else
> + clk_pll2_rate = 0;
> +
> + hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate);
> + ep93xx_clk_data->hws[EP93XX_CLK_PLL2] = hw;
> + clk_hw_register_clkdev(hw, NULL, "pll2");
> +
> + ep93xx_clk_data->num = EP93XX_NUM_CLKS;
> + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ep93xx_clk_data);
> +
> + pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
> + clk_pll1_rate / 1000000, clk_pll2_rate / 1000000);
> + pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
> + clk_f_rate / 1000000, clk_h_rate / 1000000,
> + clk_p_rate / 1000000);
> +}
> +CLK_OF_DECLARE_DRIVER(ep93xx_cc, "cirrus,ep9301-syscon", ep93xx_clock_init);
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 00/43] ep93xx device tree conversion
@ 2023-04-24 12:34 Nikita Shubin
2023-04-24 11:31 ` Arnd Bergmann
` (7 more replies)
0 siblings, 8 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-04-24 12:34 UTC (permalink / raw)
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S. Miller, Jonathan Neuschäfer, Russell King (Oracle),
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Arnd Bergmann,
Bartosz Golaszewski, Brian Norris, Chuanhong Guo, Conor Dooley,
Damien Le Moal, Daniel Lezcano, Dmitry Torokhov,
Emil Renner Berthing, Eric Dumazet, Florian Fainelli,
Guenter Roeck, Hartley Sweeten, Heiko Stuebner, Hitomi Hasegawa,
Jakub Kicinski, Jaroslav Kysela, Jean Delvare, Joel Stanley,
Jonathan Cameron, Krzysztof Kozlowski, Le Moal, Liam Girdwood,
Liang Yang, Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, linux-gpio, linux-ide, linux-input,
linux-kernel, linux-mtd, linux-pm, linux-pwm, linux-rtc,
linux-spi, linux-watchdog, netdev, soc
This series aims to convert ep93xx from platform to full device tree support.
Tested on ts7250 64 RAM/128 MiB Nand flash, edb9302.
Thank you Linus and Arnd for your support, review and comments, sorry if i missed something -
these series are quite big for me.
Big thanks to Alexander Sverdlin for his testing, support, review, fixes and patches.
Alexander Sverdlin (4):
ARM: dts: ep93xx: Add ADC node
ARM: dts: ep93xx: Add I2S and AC97 nodes
ARM: dts: ep93xx: Add EDB9302 DT
ASoC: cirrus: edb93xx: Delete driver
Nikita Shubin (39):
gpio: ep93xx: split device in multiple
soc: Add SoC driver for Cirrus ep93xx
dt-bindings: pinctrl: Add DT bindings ep93xx pinctrl
pinctrl: add a Cirrus ep93xx SoC pin controller
dt-bindings: timers: add DT bindings for Cirrus EP93xx
clocksource: ep93xx: Add driver for Cirrus Logic EP93xx
dt-bindings: rtc: add DT bindings for Cirrus EP93xx
rtc: ep93xx: add DT support for Cirrus EP93xx
dt-bindings: watchdog: add DT bindings for Cirrus EP93x
watchdog: ep93xx: add DT support for Cirrus EP93xx
dt-bindings: clock: add DT bindings for Cirrus EP93xx
clk: ep93xx: add DT support for Cirrus EP93xx
power: reset: Add a driver for the ep93xx reset
dt-bindings: pwm: Add DT bindings ep93xx PWM
pwm: ep93xx: add DT support for Cirrus EP93xx
dt-bindings: spi: Add DT bindings ep93xx spi
spi: ep93xx: add DT support for Cirrus EP93xx
dt-bindings: net: Add DT bindings ep93xx eth
net: cirrus: add DT support for Cirrus EP93xx
dt-bindings: dma: Add DT bindings ep93xx dma
dma: cirrus: add DT support for Cirrus EP93xx
dt-bindings: mtd: add DT bindings for ts7250 nand
mtd: ts72xx_nand: add platform helper
dt-bindings: ata: Add DT bindings ep93xx pata
pata: cirrus: add DT support for Cirrus EP93xx
dt-bindings: input: Add DT bindings ep93xx keypad
input: keypad: ep93xx: add DT support for Cirrus EP93xx
dt-bindings: rtc: Add DT binding m48t86 rtc
rtc: m48t86: add DT support for m48t86
dt-bindings: wdt: Add DT binding ts72xx wdt
wdt: ts72xx: add DT support for ts72xx
dt-bindings: gpio: Add DT bindings ep93xx gpio
gpio: ep93xx: add DT support for gpio-ep93xx
ARM: dts: add device tree for ep93xx Soc
ARM: ep93xx: DT for the Cirrus ep93xx SoC platforms
pwm: ep93xx: drop legacy pinctrl
input: keypad: ep93xx: drop legacy pinctrl
ARM: ep93xx: soc: drop defines
ARM: ep93xx: delete all boardfiles
.../devicetree/bindings/arm/ep93xx.yaml | 99 +
.../bindings/ata/cirrus,ep93xx-pata.yaml | 40 +
.../bindings/dma/cirrus,ep93xx-dma-m2m.yaml | 66 +
.../bindings/dma/cirrus,ep93xx-dma-m2p.yaml | 102 +
.../devicetree/bindings/gpio/gpio-ep93xx.yaml | 161 ++
.../bindings/input/cirrus,ep93xx-keypad.yaml | 123 ++
.../bindings/mtd/technologic,nand.yaml | 56 +
.../bindings/net/cirrus,ep93xx_eth.yaml | 51 +
.../pinctrl/cirrus,ep93xx-pinctrl.yaml | 66 +
.../bindings/pwm/cirrus,ep93xx-pwm.yaml | 45 +
.../bindings/rtc/cirrus,ep93xx-rtc.yaml | 32 +
.../bindings/rtc/dallas,rtc-m48t86.yaml | 33 +
.../devicetree/bindings/spi/spi-ep93xx.yaml | 68 +
.../bindings/timer/cirrus,ep93xx-timer.yaml | 41 +
.../bindings/watchdog/cirrus,ep93xx-wdt.yaml | 38 +
.../watchdog/technologic,ts72xx-wdt.yaml | 39 +
arch/arm/Makefile | 1 -
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/ep93xx-bk3.dts | 96 +
arch/arm/boot/dts/ep93xx-edb9302.dts | 150 ++
arch/arm/boot/dts/ep93xx-ts7250.dts | 113 ++
arch/arm/boot/dts/ep93xx.dtsi | 466 +++++
arch/arm/mach-ep93xx/Kconfig | 20 +-
arch/arm/mach-ep93xx/Makefile | 11 -
arch/arm/mach-ep93xx/core.c | 1017 ----------
arch/arm/mach-ep93xx/dma.c | 114 --
arch/arm/mach-ep93xx/edb93xx.c | 344 ----
arch/arm/mach-ep93xx/ep93xx-regs.h | 38 -
arch/arm/mach-ep93xx/gpio-ep93xx.h | 111 --
arch/arm/mach-ep93xx/hardware.h | 25 -
arch/arm/mach-ep93xx/irqs.h | 76 -
arch/arm/mach-ep93xx/platform.h | 42 -
arch/arm/mach-ep93xx/soc.h | 212 --
arch/arm/mach-ep93xx/ts72xx.c | 422 ----
arch/arm/mach-ep93xx/ts72xx.h | 94 -
arch/arm/mach-ep93xx/vision_ep9307.c | 311 ---
drivers/ata/pata_ep93xx.c | 9 +
drivers/clk/Kconfig | 8 +
drivers/clk/Makefile | 1 +
.../clock.c => drivers/clk/clk-ep93xx.c | 491 +++--
drivers/clocksource/Kconfig | 11 +
drivers/clocksource/Makefile | 1 +
.../clocksource}/timer-ep93xx.c | 143 +-
drivers/dma/ep93xx_dma.c | 119 +-
drivers/gpio/gpio-ep93xx.c | 329 ++--
drivers/input/keyboard/ep93xx_keypad.c | 25 +-
drivers/mtd/nand/raw/Kconfig | 8 +
drivers/mtd/nand/raw/Makefile | 1 +
drivers/mtd/nand/raw/ts72xx_nand.c | 94 +
drivers/net/ethernet/cirrus/ep93xx_eth.c | 49 +-
drivers/pinctrl/Kconfig | 7 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-ep93xx.c | 1698 +++++++++++++++++
drivers/power/reset/Kconfig | 10 +
drivers/power/reset/Makefile | 1 +
drivers/power/reset/ep93xx-restart.c | 65 +
drivers/pwm/pwm-ep93xx.c | 24 +-
drivers/rtc/rtc-ep93xx.c | 8 +
drivers/rtc/rtc-m48t86.c | 10 +
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/cirrus/Kconfig | 11 +
drivers/soc/cirrus/Makefile | 2 +
drivers/soc/cirrus/soc-ep93xx.c | 134 ++
drivers/spi/spi-ep93xx.c | 31 +-
drivers/watchdog/ep93xx_wdt.c | 8 +
drivers/watchdog/ts72xx_wdt.c | 8 +
.../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +
include/linux/platform_data/dma-ep93xx.h | 3 +
include/linux/soc/cirrus/ep93xx.h | 28 +-
sound/soc/cirrus/Kconfig | 9 -
sound/soc/cirrus/Makefile | 4 -
sound/soc/cirrus/edb93xx.c | 119 --
73 files changed, 4796 insertions(+), 3453 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
create mode 100644 Documentation/devicetree/bindings/ata/cirrus,ep93xx-pata.yaml
create mode 100644 Documentation/devicetree/bindings/dma/cirrus,ep93xx-dma-m2m.yaml
create mode 100644 Documentation/devicetree/bindings/dma/cirrus,ep93xx-dma-m2p.yaml
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ep93xx.yaml
create mode 100644 Documentation/devicetree/bindings/input/cirrus,ep93xx-keypad.yaml
create mode 100644 Documentation/devicetree/bindings/mtd/technologic,nand.yaml
create mode 100644 Documentation/devicetree/bindings/net/cirrus,ep93xx_eth.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,ep93xx-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pwm/cirrus,ep93xx-pwm.yaml
create mode 100644 Documentation/devicetree/bindings/rtc/cirrus,ep93xx-rtc.yaml
create mode 100644 Documentation/devicetree/bindings/rtc/dallas,rtc-m48t86.yaml
create mode 100644 Documentation/devicetree/bindings/spi/spi-ep93xx.yaml
create mode 100644 Documentation/devicetree/bindings/timer/cirrus,ep93xx-timer.yaml
create mode 100644 Documentation/devicetree/bindings/watchdog/cirrus,ep93xx-wdt.yaml
create mode 100644 Documentation/devicetree/bindings/watchdog/technologic,ts72xx-wdt.yaml
create mode 100644 arch/arm/boot/dts/ep93xx-bk3.dts
create mode 100644 arch/arm/boot/dts/ep93xx-edb9302.dts
create mode 100644 arch/arm/boot/dts/ep93xx-ts7250.dts
create mode 100644 arch/arm/boot/dts/ep93xx.dtsi
delete mode 100644 arch/arm/mach-ep93xx/Makefile
delete mode 100644 arch/arm/mach-ep93xx/core.c
delete mode 100644 arch/arm/mach-ep93xx/dma.c
delete mode 100644 arch/arm/mach-ep93xx/edb93xx.c
delete mode 100644 arch/arm/mach-ep93xx/ep93xx-regs.h
delete mode 100644 arch/arm/mach-ep93xx/gpio-ep93xx.h
delete mode 100644 arch/arm/mach-ep93xx/hardware.h
delete mode 100644 arch/arm/mach-ep93xx/irqs.h
delete mode 100644 arch/arm/mach-ep93xx/platform.h
delete mode 100644 arch/arm/mach-ep93xx/soc.h
delete mode 100644 arch/arm/mach-ep93xx/ts72xx.c
delete mode 100644 arch/arm/mach-ep93xx/ts72xx.h
delete mode 100644 arch/arm/mach-ep93xx/vision_ep9307.c
rename arch/arm/mach-ep93xx/clock.c => drivers/clk/clk-ep93xx.c (60%)
rename {arch/arm/mach-ep93xx => drivers/clocksource}/timer-ep93xx.c (51%)
create mode 100644 drivers/mtd/nand/raw/ts72xx_nand.c
create mode 100644 drivers/pinctrl/pinctrl-ep93xx.c
create mode 100644 drivers/power/reset/ep93xx-restart.c
create mode 100644 drivers/soc/cirrus/Kconfig
create mode 100644 drivers/soc/cirrus/Makefile
create mode 100644 drivers/soc/cirrus/soc-ep93xx.c
create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
delete mode 100644 sound/soc/cirrus/edb93xx.c
--
2.39.2
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
2023-04-24 11:31 ` Arnd Bergmann
@ 2023-04-24 12:34 ` Nikita Shubin
2023-04-24 13:28 ` Rob Herring
2023-04-28 23:15 ` Stephen Boyd
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
` (5 subsequent siblings)
7 siblings, 2 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-04-24 12:34 UTC (permalink / raw)
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin, Rob Herring,
Krzysztof Kozlowski, Michael Turquette, Stephen Boyd,
Hartley Sweeten, devicetree, linux-kernel, linux-clk
This adds device tree bindings for the Cirrus Logic EP93xx
clock block used in these SoCs.
Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
---
.../devicetree/bindings/arm/ep93xx.yaml | 102 ++++++++++++++++++
.../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +++++++++
2 files changed, 155 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
diff --git a/Documentation/devicetree/bindings/arm/ep93xx.yaml b/Documentation/devicetree/bindings/arm/ep93xx.yaml
new file mode 100644
index 000000000000..de7020f4f356
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/ep93xx.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/ep93xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logick EP93xx device tree bindings
+
+description: |+
+ The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
+
+maintainers:
+ - Hartley Sweeten <hsweeten@visionengravers.com>
+ - Alexander Sverdlin <alexander.sverdlin@gmail.com>
+ - Nikita Shubin <nikita.shubin@maquefel.me>
+
+properties:
+ $nodename:
+ const: '/'
+ compatible:
+ oneOf:
+ - description: The TS-7250 is a compact, full-featured Single Board Computer (SBC)
+ based upon the Cirrus EP9302 ARM9 CPU.
+ items:
+ - const: technologic,ts7250
+ - const: liebherr,bk3
+ - const: cirrus,ep9301
+ - const: cirrus,edb9302
+
+ soc:
+ type: object
+ patternProperties:
+ "^.*syscon@80930000$":
+ type: object
+ properties:
+ compatible:
+ items:
+ - const: cirrus,ep9301-syscon
+ - const: syscon
+ - const: simple-mfd
+ ep9301-reboot:
+ type: object
+ properties:
+ compatible:
+ const: cirrus,ep9301-reboot
+ required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - ep9301-reboot
+
+ "^.*timer@80810000$":
+ type: object
+ properties:
+ compatible:
+ const: cirrus,ep9301-timer
+
+ required:
+ - syscon@80930000
+ - timer@80810000
+
+required:
+ - compatible
+ - soc
+
+additionalProperties: true
+
+examples:
+ - |
+ / {
+ compatible = "technologic,ts7250", "cirrus,ep9301";
+ model = "TS-7250 SBC";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "simple-bus";
+
+ syscon: syscon@80930000 {
+ compatible = "cirrus,ep9301-syscon",
+ "syscon", "simple-mfd";
+ reg = <0x80930000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+
+ ep9301-reboot {
+ compatible = "cirrus,ep9301-reboot";
+ };
+ };
+
+ timer: timer@80810000 {
+ compatible = "cirrus,ep9301-timer";
+ reg = <0x80810000 0x100>;
+ interrupt-parent = <&vic1>;
+ interrupts = <19>;
+ };
+ };
+ };
+
+...
diff --git a/include/dt-bindings/clock/cirrus,ep93xx-clock.h b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
new file mode 100644
index 000000000000..ad796314fb11
--- /dev/null
+++ b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
+#define DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
+
+#define EP93XX_CLK_XTALI 0
+
+#define EP93XX_CLK_PLL1 1
+#define EP93XX_CLK_FCLK 2
+#define EP93XX_CLK_HCLK 3
+#define EP93XX_CLK_PCLK 4
+#define EP93XX_CLK_PLL2 5
+
+#define EP93XX_CLK_UART 6
+
+#define EP93XX_CLK_UART1 7
+#define EP93XX_CLK_UART2 8
+#define EP93XX_CLK_UART3 9
+
+#define EP93XX_CLK_M2M0 10
+#define EP93XX_CLK_M2M1 11
+
+#define EP93XX_CLK_M2P0 12
+#define EP93XX_CLK_M2P1 13
+#define EP93XX_CLK_M2P2 14
+#define EP93XX_CLK_M2P3 15
+#define EP93XX_CLK_M2P4 16
+#define EP93XX_CLK_M2P5 17
+#define EP93XX_CLK_M2P6 18
+#define EP93XX_CLK_M2P7 19
+#define EP93XX_CLK_M2P8 20
+#define EP93XX_CLK_M2P9 21
+
+#define EP93XX_CLK_SPI 22
+
+#define EP93XX_CLK_USB 23
+
+#define EP93XX_CLK_ADC 24
+#define EP93XX_CLK_ADC_EN 25
+
+#define EP93XX_CLK_KEYPAD 26
+
+#define EP93XX_CLK_PWM 27
+
+#define EP93XX_CLK_VIDEO 28
+
+#define EP93XX_CLK_I2S_MCLK 29
+#define EP93XX_CLK_I2S_SCLK 30
+#define EP93XX_CLK_I2S_LRCLK 31
+
+
+#define EP93XX_NUM_CLKS (EP93XX_CLK_I2S_LRCLK + 1)
+
+#endif /* DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H */
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
2023-04-24 11:31 ` Arnd Bergmann
2023-04-24 12:34 ` [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx Nikita Shubin
@ 2023-04-24 12:34 ` Nikita Shubin
2023-04-24 12:01 ` Christophe JAILLET
` (2 more replies)
2023-04-26 20:56 ` [PATCH 00/43] ep93xx device tree conversion Linus Walleij
` (4 subsequent siblings)
7 siblings, 3 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-04-24 12:34 UTC (permalink / raw)
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, Stephen Boyd, linux-kernel, linux-clk
This is a rewrite of EP93xx timer driver in
arch/arm/mach-ep93xx/clock.c trying to do everything
the device tree way:
- convert to syscon driver
- provide clock acces via of
Co-developed-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
---
Notes:
rfc->v0
Linus Walleij:
- renamed all __underscore
Alexander Sverdlin:
- "Logick" -> "Logic"
Changes by Alexander Sverdlin:
- remove pr_info
- DIV_ROUND_UP_ULL -> DIV_ROUND_CLOSEST
- fix zeroing bitfield in ep93xx_div_set_rate
- add sanity check for EP93XX_SYSCON_CHIPID_ID
- use bit index for DMA clock's
- ep93xx_clk_register_gate() takes bit index, not mask
- remove redundant define
- use DIV_ROUND_CLOSEST() everywhere to achieve frequencies closer to those
requested
- Add the forgotten configuration from the deleted
arch/arm/mach-ep93xx/core.c
drivers/clk/Kconfig | 8 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-ep93xx.c | 880 +++++++++++++++++++++++++++++++++++++++
3 files changed, 889 insertions(+)
create mode 100644 drivers/clk/clk-ep93xx.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1eef05bb1f99..d3ad975b688e 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -436,6 +436,14 @@ config COMMON_CLK_K210
help
Support for the Canaan Kendryte K210 RISC-V SoC clocks.
+config COMMON_CLK_EP93XX
+ bool "Clock driver for Cirrus Logic ep93xx SoC"
+ depends on ARCH_EP93XX || COMPILE_TEST
+ select MFD_SYSCON
+ select REGMAP
+ help
+ This driver supports the SoC clocks on the Cirrus Logic ep93xx.
+
source "drivers/clk/actions/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/baikal-t1/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e3ca0d058a25..deec25ffd004 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
+obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c
new file mode 100644
index 000000000000..e5913fc4c39b
--- /dev/null
+++ b/drivers/clk/clk-ep93xx.c
@@ -0,0 +1,880 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Clock control for Cirrus EP93xx chips.
+ * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
+ *
+ * Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ */
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/cirrus/ep93xx.h>
+#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
+
+#include <asm/div64.h>
+
+#define EP93XX_EXT_CLK_RATE 14745600
+#define EP93XX_EXT_RTC_RATE 32768
+
+#define EP93XX_SYSCON_POWER_STATE 0x00
+#define EP93XX_SYSCON_PWRCNT 0x04
+#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
+#define EP93XX_SYSCON_PWRCNT_USH_EN 28
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
+#define EP93XX_SYSCON_CLKSET1 0x20
+#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
+#define EP93XX_SYSCON_CLKSET2 0x24
+#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
+#define EP93XX_SYSCON_DEVCFG 0x80
+#define EP93XX_SYSCON_DEVCFG_U3EN 24
+#define EP93XX_SYSCON_DEVCFG_U2EN 20
+#define EP93XX_SYSCON_DEVCFG_U1EN 18
+#define EP93XX_SYSCON_VIDCLKDIV 0x84
+#define EP93XX_SYSCON_CLKDIV_ENABLE 15
+#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
+#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
+#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
+#define EP93XX_SYSCON_I2SCLKDIV 0x8c
+#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
+#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
+#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
+#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
+#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
+#define EP93XX_SYSCON_CHIPID 0x94
+#define EP93XX_SYSCON_CHIPID_ID 0x9213
+
+static DEFINE_SPINLOCK(clk_lock);
+static struct regmap *ep93xx_map;
+#define ep93xx_regmap_read(reg, val) regmap_read(ep93xx_map, reg, val)
+
+/* Keeps track of all clocks */
+static struct clk_hw_onecell_data *ep93xx_clk_data;
+
+static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
+static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
+static char pclk_divisors[] = { 1, 2, 4, 8 };
+
+static char adc_divisors[] = { 16, 4 };
+static char sclk_divisors[] = { 2, 4 };
+static char lrclk_divisors[] = { 32, 64, 128 };
+
+static const char * const mux_parents[] = {
+ "xtali",
+ "pll1",
+ "pll2"
+};
+
+/*
+ * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
+ */
+static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word)
+{
+ int i;
+
+ rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
+ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
+ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
+ for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
+ rate >>= 1;
+
+ return (unsigned long)rate;
+}
+
+struct clk_psc {
+ struct clk_hw hw;
+ unsigned int reg;
+ u8 bit_idx;
+ u32 mask;
+ u8 shift;
+ u8 width;
+ char *div;
+ u8 num_div;
+ spinlock_t *lock;
+};
+
+#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
+
+static int ep93xx_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+
+ return (val & BIT(psc->bit_idx)) ? 1 : 0;
+}
+
+static int ep93xx_clk_enable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val |= BIT(psc->bit_idx);
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+
+ return 0;
+}
+
+static void ep93xx_clk_disable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~BIT(psc->bit_idx);
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+}
+
+static const struct clk_ops clk_ep93xx_gate_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+};
+
+static struct clk_hw *ep93xx_clk_register_gate(const char *name,
+ const char *parent_name,
+ unsigned int reg,
+ u8 bit_idx)
+{
+ struct clk_init_data init;
+ struct clk_psc *psc;
+ struct clk *clk;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_ep93xx_gate_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ psc->reg = reg;
+ psc->bit_idx = bit_idx;
+ psc->hw.init = &init;
+ psc->lock = &clk_lock;
+
+ clk = clk_register(NULL, &psc->hw);
+ if (IS_ERR(clk)) {
+ kfree(psc);
+ return ERR_CAST(clk);
+ }
+
+ return &psc->hw;
+}
+
+static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
+ return 0;
+
+ if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
+ return 1;
+
+ return 2;
+}
+
+static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (index >= ARRAY_SIZE(mux_parents))
+ return -EINVAL;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
+
+ if (index != 0) {
+ val |= EP93XX_SYSCON_CLKDIV_ESEL;
+ val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
+ }
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+
+ return 0;
+}
+
+static bool is_best(unsigned long rate, unsigned long now,
+ unsigned long best)
+{
+ return abs(rate - now) < abs(rate - best);
+}
+
+static int ep93xx_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long rate = req->rate;
+ struct clk *parent_best = NULL;
+ unsigned long parent_rate;
+ unsigned long best_rate = 0, actual_rate, mclk_rate;
+ unsigned long parent_rate_best;
+ int div, pdiv;
+ int i;
+
+ /*
+ * Try the two pll's and the external clock
+ * Because the valid predividers are 2, 2.5 and 3, we multiply
+ * all the clocks by 2 to avoid floating point math.
+ *
+ * This is based on the algorithm in the ep93xx raster guide:
+ * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
+ *
+ */
+ for (i = 0; i < ARRAY_SIZE(mux_parents); i++) {
+ struct clk *parent = clk_get_sys(mux_parents[i], NULL);
+
+ parent_rate = clk_get_rate(parent);
+ mclk_rate = parent_rate * 2;
+
+ /* Try each predivider value */
+ for (pdiv = 4; pdiv <= 6; pdiv++) {
+ div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
+ if (div < 1 || div > 127)
+ continue;
+
+ actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
+
+ if (is_best(rate, actual_rate, best_rate)) {
+ best_rate = actual_rate;
+ parent_rate_best = parent_rate;
+ parent_best = parent;
+ }
+ }
+ }
+
+ if (!parent_best)
+ return -EINVAL;
+
+ req->best_parent_rate = parent_rate_best;
+ req->best_parent_hw = __clk_get_hw(parent_best);
+ req->rate = best_rate;
+
+ return 0;
+}
+
+static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long rate = 0;
+ u32 val;
+ int pdiv, div;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
+ div = val & 0x7f;
+ if (div > 0)
+ rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
+
+ return rate;
+}
+
+static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ int pdiv, div, npdiv, ndiv;
+ unsigned long actual_rate, mclk_rate, rate_err = -1;
+ int found = 0;
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ mclk_rate = parent_rate * 2;
+
+ for (pdiv = 4; pdiv <= 6; pdiv++) {
+ div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
+ if (div < 1 || div > 127)
+ continue;
+
+ actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
+
+ if (!found || abs(actual_rate - rate) < rate_err) {
+ npdiv = pdiv - 3;
+ ndiv = div;
+ rate_err = abs(actual_rate - rate);
+ found = 1;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ /* Clear old dividers */
+ val &= ~0x37f;
+
+ /* Set the new pdiv and div bits for the new clock rate */
+ val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ return 0;
+}
+
+static const struct clk_ops clk_ddiv_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+ .get_parent = ep93xx_mux_get_parent,
+ .set_parent = ep93xx_mux_set_parent_lock,
+ .determine_rate = ep93xx_mux_determine_rate,
+ .recalc_rate = ep93xx_ddiv_recalc_rate,
+ .set_rate = ep93xx_ddiv_set_rate,
+};
+
+static struct clk_hw *clk_hw_register_ddiv(const char *name,
+ unsigned int reg,
+ u8 bit_idx)
+{
+ struct clk_init_data init;
+ struct clk_psc *psc;
+ struct clk *clk;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_ddiv_ops;
+ init.flags = 0;
+ init.parent_names = mux_parents;
+ init.num_parents = ARRAY_SIZE(mux_parents);
+
+ psc->reg = reg;
+ psc->bit_idx = bit_idx;
+ psc->lock = &clk_lock;
+ psc->hw.init = &init;
+
+ clk = clk_register(NULL, &psc->hw);
+ if (IS_ERR(clk)) {
+ kfree(psc);
+ return ERR_CAST(clk);
+ }
+
+ return &psc->hw;
+}
+
+static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+ u8 index;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ index = (val & psc->mask) >> psc->shift;
+ if (index > psc->num_div)
+ return 0;
+
+ return DIV_ROUND_CLOSEST(parent_rate, psc->div[index]);
+}
+
+static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long best = 0, now;
+ bool assigned = false;
+ int i;
+
+ for (i = 0; i < psc->num_div; i++) {
+ if ((rate * psc->div[i]) == *parent_rate)
+ return rate;
+
+ now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
+
+ if (!assigned || is_best(rate, now, best))
+ best = now;
+ assigned = true;
+ }
+
+ return best;
+}
+
+static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+ int i;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~psc->mask;
+ for (i = 0; i < psc->num_div; i++)
+ if (rate == DIV_ROUND_CLOSEST(parent_rate, psc->div[i])) {
+ val |= i << psc->shift;
+ break;
+ }
+
+ if (i == psc->num_div)
+ return -EINVAL;
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ return 0;
+}
+
+static const struct clk_ops ep93xx_div_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+ .recalc_rate = ep93xx_div_recalc_rate,
+ .round_rate = ep93xx_div_round_rate,
+ .set_rate = ep93xx_div_set_rate,
+};
+
+static struct clk_hw *clk_hw_register_div(const char *name,
+ const char *parent_name,
+ unsigned int reg,
+ u8 enable_bit,
+ u8 shift,
+ u8 width,
+ char *clk_divisors,
+ u8 num_div)
+{
+ struct clk_init_data init;
+ struct clk_psc *psc;
+ struct clk *clk;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &ep93xx_div_ops;
+ init.flags = 0;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = 1;
+
+ psc->reg = reg;
+ psc->bit_idx = enable_bit;
+ psc->mask = GENMASK(shift + width - 1, shift);
+ psc->shift = shift;
+ psc->div = clk_divisors;
+ psc->num_div = num_div;
+ psc->lock = &clk_lock;
+ psc->hw.init = &init;
+
+ clk = clk_register(NULL, &psc->hw);
+ if (IS_ERR(clk)) {
+ kfree(psc);
+ return ERR_CAST(clk);
+ }
+
+ return &psc->hw;
+}
+
+struct ep93xx_gate {
+ unsigned int idx;
+ unsigned int bit;
+ const char *dev_id;
+ const char *con_id;
+};
+
+static struct ep93xx_gate ep93xx_uarts[] = {
+ {EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL},
+ {EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL},
+ {EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL},
+};
+
+static void ep93xx_uart_clock_init(void)
+{
+ unsigned int i;
+ struct clk_hw *hw;
+ u32 val;
+ unsigned int clk_uart_div;
+
+ ep93xx_regmap_read(EP93XX_SYSCON_PWRCNT, &val);
+ if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
+ clk_uart_div = 1;
+ else
+ clk_uart_div = 2;
+
+ hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_UART] = hw;
+
+ /* parenting uart gate clocks to uart clock */
+ for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
+ hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id,
+ "uart",
+ EP93XX_SYSCON_DEVCFG,
+ ep93xx_uarts[i].bit);
+
+ ep93xx_clk_data->hws[ep93xx_uarts[i].idx] = hw;
+ }
+}
+
+static struct ep93xx_gate ep93xx_dmas[] = {
+ {EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"},
+ {EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"},
+ {EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"},
+ {EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"},
+ {EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"},
+ {EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"},
+ {EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"},
+ {EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"},
+ {EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"},
+ {EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"},
+ {EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"},
+ {EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"},
+};
+
+static void ep93xx_dma_clock_init(void __iomem *base)
+{
+ int i;
+ struct clk_hw *hw;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
+ hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id,
+ "hclk", 0,
+ base + EP93XX_SYSCON_PWRCNT,
+ ep93xx_dmas[i].bit,
+ 0,
+ &clk_lock);
+
+ ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL);
+ if (ret) {
+ pr_err("%s: failed to register lookup %s\n",
+ __func__, ep93xx_dmas[i].con_id);
+ continue;
+ }
+
+ ep93xx_clk_data->hws[ep93xx_dmas[i].idx] = hw;
+ }
+}
+
+static int ep93xx_clk_probe(struct platform_device *pdev)
+{
+ void __iomem *base;
+ unsigned int clk_usb_div;
+ unsigned long clk_spi_div;
+ struct clk_hw *hw;
+ struct device *dev = &pdev->dev;
+ u32 value;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
+ clk_usb_div = (((value >> 28) & 0xf) + 1);
+ hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
+ hw = clk_hw_register_gate(NULL, "ohci-platform",
+ "usb_clk", 0,
+ base + EP93XX_SYSCON_PWRCNT,
+ EP93XX_SYSCON_PWRCNT_USH_EN,
+ 0,
+ &clk_lock);
+ clk_hw_register_clkdev(hw, NULL, "ohci-platform");
+ ep93xx_clk_data->hws[EP93XX_CLK_USB] = hw;
+
+ /*
+ * EP93xx SSP clock rate was doubled in version E2. For more information
+ * see:
+ * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+ clk_spi_div = 1;
+ if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+ clk_spi_div = 2;
+ hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div);
+ clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0");
+ ep93xx_clk_data->hws[EP93XX_CLK_SPI] = hw;
+
+ /* pwm clock */
+ hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1);
+ clk_hw_register_clkdev(hw, "pwm_clk", NULL);
+ ep93xx_clk_data->hws[EP93XX_CLK_PWM] = hw;
+
+ ep93xx_uart_clock_init();
+
+ /* touchscreen/adc clock */
+ hw = clk_hw_register_div("ep93xx-adc",
+ "xtali",
+ EP93XX_SYSCON_KEYTCHCLKDIV,
+ EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
+ EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
+ 1,
+ adc_divisors,
+ ARRAY_SIZE(adc_divisors));
+
+ clk_hw_register_clkdev(hw, NULL, "ep93xx-adc");
+ ep93xx_clk_data->hws[EP93XX_CLK_ADC] = hw;
+
+ /* keypad clock */
+ hw = clk_hw_register_div("ep93xx-keypad",
+ "xtali",
+ EP93XX_SYSCON_KEYTCHCLKDIV,
+ EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
+ EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
+ 1,
+ adc_divisors,
+ ARRAY_SIZE(adc_divisors));
+
+ clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad");
+ ep93xx_clk_data->hws[EP93XX_CLK_KEYPAD] = hw;
+
+ /* On reset PDIV and VDIV is set to zero, while PDIV zero
+ * means clock disable, VDIV shouldn't be zero.
+ * So i set both dividers to minimum.
+ */
+ /* ENA - Enable CLK divider. */
+ /* PDIV - 00 - Disable clock */
+ /* VDIV - at least 2 */
+ /* Check and enable video clk registers */
+ ep93xx_regmap_read(EP93XX_SYSCON_VIDCLKDIV, &value);
+ value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
+ ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV);
+
+ /* check and enable i2s clk registers */
+ ep93xx_regmap_read(EP93XX_SYSCON_I2SCLKDIV, &value);
+ value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
+ /*
+ * Override the SAI_MSTR_CLK_CFG from the I2S block and use the
+ * I2SClkDiv Register settings. LRCLK transitions on the falling SCLK
+ * edge.
+ */
+ value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
+ ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV);
+
+ /* video clk */
+ hw = clk_hw_register_ddiv("ep93xx-fb",
+ EP93XX_SYSCON_VIDCLKDIV,
+ EP93XX_SYSCON_CLKDIV_ENABLE);
+
+ clk_hw_register_clkdev(hw, NULL, "ep93xx-fb");
+ ep93xx_clk_data->hws[EP93XX_CLK_VIDEO] = hw;
+
+ /* i2s clk */
+ hw = clk_hw_register_ddiv("mclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_CLKDIV_ENABLE);
+
+ clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s");
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_MCLK] = hw;
+
+ /* i2s sclk */
+#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16
+#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1
+ hw = clk_hw_register_div("sclk",
+ "mclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_I2SCLKDIV_SENA,
+ EP93XX_I2SCLKDIV_SDIV_SHIFT,
+ EP93XX_I2SCLKDIV_SDIV_WIDTH,
+ sclk_divisors,
+ ARRAY_SIZE(sclk_divisors));
+
+ clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s");
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_SCLK] = hw;
+
+ /* i2s lrclk */
+#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17
+#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 2
+ hw = clk_hw_register_div("lrclk",
+ "sclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_I2SCLKDIV_SENA,
+ EP93XX_I2SCLKDIV_LRDIV32_SHIFT,
+ EP93XX_I2SCLKDIV_LRDIV32_WIDTH,
+ lrclk_divisors,
+ ARRAY_SIZE(lrclk_divisors));
+
+ clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s");
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_LRCLK] = hw;
+
+ /* IrDa clk uses same pattern but no init code presents in original clock driver */
+ return 0;
+}
+
+static const struct of_device_id ep93xx_clk_dt_ids[] = {
+ { .compatible = "cirrus,ep9301-syscon", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver ep93xx_clk_driver = {
+ .probe = ep93xx_clk_probe,
+ .driver = {
+ .name = "ep93xx-clk",
+ .of_match_table = ep93xx_clk_dt_ids,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(ep93xx_clk_driver);
+
+static void __init ep93xx_clock_init(struct device_node *np)
+{
+ void __iomem *base;
+ int i;
+ int ret;
+ u32 value;
+ struct clk_hw *hw;
+ unsigned long clk_pll1_rate;
+ unsigned long clk_f_rate;
+ unsigned long clk_h_rate;
+ unsigned long clk_p_rate;
+ unsigned long clk_pll2_rate;
+ unsigned int clk_f_div;
+ unsigned int clk_h_div;
+ unsigned int clk_p_div;
+
+ ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
+ EP93XX_NUM_CLKS),
+ GFP_KERNEL);
+
+ if (!ep93xx_clk_data)
+ return;
+
+ /*
+ * This way all clock fetched before the platform device probes,
+ * except those we assign here for early use, will be deferred.
+ */
+ for (i = 0; i < EP93XX_NUM_CLKS; i++)
+ ep93xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+ base = of_iomap(np, 0);
+ /* Remap the system controller for the exclusive register */
+ if (IS_ERR(base)) {
+ pr_err("failed to map base\n");
+ return;
+ }
+
+ ep93xx_map = syscon_node_to_regmap(np);
+ if (IS_ERR(ep93xx_map)) {
+ pr_err("no syscon regmap\n");
+ return;
+ }
+
+ /*
+ * We check that the regmap works on this very first access,
+ * but as this is an MMIO-backed regmap, subsequent regmap
+ * access is not going to fail and we skip error checks from
+ * this point.
+ */
+ ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
+ if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
+ pr_err("failed to read global status register\n");
+ return;
+ }
+
+ hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE);
+ clk_hw_register_clkdev(hw, NULL, "xtali");
+
+ /* Determine the bootloader configured pll1 rate */
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET1, &value);
+ if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
+ clk_pll1_rate = EP93XX_EXT_CLK_RATE;
+ else
+ clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
+
+ hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate);
+ clk_hw_register_clkdev(hw, NULL, "pll1");
+ ep93xx_clk_data->hws[EP93XX_CLK_PLL1] = hw;
+
+ /* Initialize the pll1 derived clocks */
+ clk_f_div = fclk_divisors[(value >> 25) & 0x7];
+ clk_h_div = hclk_divisors[(value >> 20) & 0x7];
+ clk_p_div = pclk_divisors[(value >> 18) & 0x3];
+
+ hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div);
+ clk_f_rate = clk_get_rate(hw->clk);
+ ep93xx_clk_data->hws[EP93XX_CLK_FCLK] = hw;
+ hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div);
+ clk_h_rate = clk_get_rate(hw->clk);
+ ep93xx_clk_data->hws[EP93XX_CLK_HCLK] = hw;
+ hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div);
+ clk_p_rate = clk_get_rate(hw->clk);
+ ep93xx_clk_data->hws[EP93XX_CLK_PCLK] = hw;
+
+ clk_hw_register_clkdev(hw, "apb_pclk", NULL);
+
+ ep93xx_dma_clock_init(base);
+
+ /* Determine the bootloader configured pll2 rate */
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
+ if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
+ clk_pll2_rate = EP93XX_EXT_CLK_RATE;
+ else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
+ clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
+ else
+ clk_pll2_rate = 0;
+
+ hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate);
+ ep93xx_clk_data->hws[EP93XX_CLK_PLL2] = hw;
+ clk_hw_register_clkdev(hw, NULL, "pll2");
+
+ ep93xx_clk_data->num = EP93XX_NUM_CLKS;
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ep93xx_clk_data);
+
+ pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
+ clk_pll1_rate / 1000000, clk_pll2_rate / 1000000);
+ pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
+ clk_f_rate / 1000000, clk_h_rate / 1000000,
+ clk_p_rate / 1000000);
+}
+CLK_OF_DECLARE_DRIVER(ep93xx_cc, "cirrus,ep9301-syscon", ep93xx_clock_init);
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx
2023-04-24 12:34 ` [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx Nikita Shubin
@ 2023-04-24 13:28 ` Rob Herring
2023-04-28 23:15 ` Stephen Boyd
1 sibling, 0 replies; 26+ messages in thread
From: Rob Herring @ 2023-04-24 13:28 UTC (permalink / raw)
To: Nikita Shubin
Cc: linux-kernel, linux-clk, devicetree, Hartley Sweeten,
Linus Walleij, Stephen Boyd, Michael Turquette, Arnd Bergmann,
Krzysztof Kozlowski, Rob Herring, Alexander Sverdlin
On Mon, 24 Apr 2023 15:34:27 +0300, Nikita Shubin wrote:
> This adds device tree bindings for the Cirrus Logic EP93xx
> clock block used in these SoCs.
>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
> .../devicetree/bindings/arm/ep93xx.yaml | 102 ++++++++++++++++++
> .../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +++++++++
> 2 files changed, 155 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
> create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/arm/ep93xx.example.dtb: /: compatible: 'oneOf' conditional failed, one must be fixed:
['technologic,ts7250', 'cirrus,ep9301'] is too short
'liebherr,bk3' was expected
From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/arm/ep93xx.yaml
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20230424123522.18302-12-nikita.shubin@maquefel.me
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
2023-04-24 12:01 ` Christophe JAILLET
@ 2023-04-24 17:17 ` kernel test robot
2023-04-29 0:58 ` Stephen Boyd
2 siblings, 0 replies; 26+ messages in thread
From: kernel test robot @ 2023-04-24 17:17 UTC (permalink / raw)
To: Nikita Shubin
Cc: oe-kbuild-all, Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, Stephen Boyd, linux-kernel, linux-clk
Hi Nikita,
kernel test robot noticed the following build errors:
[auto build test ERROR on soc/for-next]
[also build test ERROR on robh/for-next linusw-pinctrl/devel linusw-pinctrl/for-next linus/master v6.3]
[cannot apply to next-20230421]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nikita-Shubin/gpio-ep93xx-split-device-in-multiple/20230424-183649
base: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
patch link: https://lore.kernel.org/r/20230424123522.18302-13-nikita.shubin%40maquefel.me
patch subject: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230425/202304250013.c9Px2Npt-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/8621eda93e4a641c57f889ac36d2386482e92157
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Nikita-Shubin/gpio-ep93xx-split-device-in-multiple/20230424-183649
git checkout 8621eda93e4a641c57f889ac36d2386482e92157
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202304250013.c9Px2Npt-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/clk/clk-ep93xx.c: In function 'ep93xx_clk_enable':
>> drivers/clk/clk-ep93xx.c:153:9: error: implicit declaration of function 'ep93xx_syscon_swlocked_write' [-Werror=implicit-function-declaration]
153 | ep93xx_syscon_swlocked_write(val, psc->reg);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/ep93xx_syscon_swlocked_write +153 drivers/clk/clk-ep93xx.c
140
141 static int ep93xx_clk_enable(struct clk_hw *hw)
142 {
143 struct clk_psc *psc = to_clk_psc(hw);
144 unsigned long flags = 0;
145 u32 val;
146
147 if (psc->lock)
148 spin_lock_irqsave(psc->lock, flags);
149
150 ep93xx_regmap_read(psc->reg, &val);
151 val |= BIT(psc->bit_idx);
152
> 153 ep93xx_syscon_swlocked_write(val, psc->reg);
154
155 if (psc->lock)
156 spin_unlock_irqrestore(psc->lock, flags);
157
158 return 0;
159 }
160
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
[not found] ` <20230424152933.48b2ede1@kernel.org>
@ 2023-04-25 9:20 ` Krzysztof Kozlowski
2023-04-25 13:27 ` Arnd Bergmann
0 siblings, 1 reply; 26+ messages in thread
From: Krzysztof Kozlowski @ 2023-04-25 9:20 UTC (permalink / raw)
To: Jakub Kicinski, Arnd Bergmann
Cc: Nikita Shubin, Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S . Miller, Jonathan Neuschäfer, Russell King,
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Bartosz Golaszewski,
Brian Norris, Chuanhong Guo, Conor.Dooley, Damien Le Moal,
Daniel Lezcano, Dmitry Torokhov, Emil Renner Berthing,
Eric Dumazet, Florian Fainelli, Guenter Roeck, Hartley Sweeten,
Heiko Stübner, Hitomi Hasegawa, Jaroslav Kysela,
Jean Delvare, Joel Stanley, Jonathan Cameron,
Krzysztof Kozlowski, Damien Le Moal, Liam Girdwood, Liang Yang,
Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, open list:GPIO SUBSYSTEM, linux-ide,
linux-input, linux-kernel, linux-mtd, linux-pm, linux-pwm,
linux-rtc, linux-spi, linux-watchdog, Netdev, soc
On 25/04/2023 00:29, Jakub Kicinski wrote:
> On Mon, 24 Apr 2023 13:31:25 +0200 Arnd Bergmann wrote:
>> Thanks a lot for your continued work. I can't merge any of this at
>> the moment since the upstream merge window just opened, but I'm
>> happy to take this all through the soc tree for 6.5, provided we
>> get the sufficient Acks from the subsystem maintainers. Merging
>> it through each individual tree would take a lot longer, so I
>> hope we can avoid that.
>
> Is there a dependency between the patches?
I didn't get entire patchset and cover letter does not mention
dependencies, but usually there shouldn't be such. Maybe for the next
versions this should be split per subsystem?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
2023-04-25 9:20 ` Krzysztof Kozlowski
@ 2023-04-25 13:27 ` Arnd Bergmann
0 siblings, 0 replies; 26+ messages in thread
From: Arnd Bergmann @ 2023-04-25 13:27 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jakub Kicinski
Cc: Nikita Shubin, Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S . Miller, Jonathan Neuschäfer, Russell King,
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Bartosz Golaszewski,
Brian Norris, Chuanhong Guo, Conor.Dooley, Damien Le Moal,
Daniel Lezcano, Dmitry Torokhov, Emil Renner Berthing,
Eric Dumazet, Florian Fainelli, Guenter Roeck, Hartley Sweeten,
Heiko Stübner, Hitomi Hasegawa, Jaroslav Kysela,
Jean Delvare, Joel Stanley, Jonathan Cameron,
Krzysztof Kozlowski, Damien Le Moal, Liam Girdwood, Liang Yang,
Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, open list:GPIO SUBSYSTEM, linux-ide,
linux-input, linux-kernel, linux-mtd, linux-pm, linux-pwm,
linux-rtc, linux-spi, linux-watchdog, Netdev, soc
On Tue, Apr 25, 2023, at 10:20, Krzysztof Kozlowski wrote:
> On 25/04/2023 00:29, Jakub Kicinski wrote:
>> On Mon, 24 Apr 2023 13:31:25 +0200 Arnd Bergmann wrote:
>>> Thanks a lot for your continued work. I can't merge any of this at
>>> the moment since the upstream merge window just opened, but I'm
>>> happy to take this all through the soc tree for 6.5, provided we
>>> get the sufficient Acks from the subsystem maintainers. Merging
>>> it through each individual tree would take a lot longer, so I
>>> hope we can avoid that.
>>
>> Is there a dependency between the patches?
>
> I didn't get entire patchset and cover letter does not mention
> dependencies, but usually there shouldn't be such. Maybe for the next
> versions this should be split per subsystem?
Clearly the last patch that removes the board files depends on
all the previous patches, but I assume that the other ones
are all independent.
We don't do complete conversions from boardfiles to DT that often
any more, but in the past we tended to do this through a cross-
subsystem branch in the soc tree, which helps do it more quickly
and is less work for Nikita. In this case, I would make it a
separate top-level branch in the soc tree.
If anyone strongly feels that the patches should go through
the subsystem trees here, we'll take the longer path and
do the changes separately, with the boardfile removal
coming a release later.
Arnd
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
` (2 preceding siblings ...)
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
@ 2023-04-26 20:56 ` Linus Walleij
[not found] ` <b5396ef5-3fed-4e98-8f37-a9cd4473bddc@sirena.org.uk>
2023-05-16 3:47 ` Florian Fainelli
` (3 subsequent siblings)
7 siblings, 1 reply; 26+ messages in thread
From: Linus Walleij @ 2023-04-26 20:56 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S. Miller, Jonathan Neuschäfer, Russell King (Oracle),
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Arnd Bergmann,
Bartosz Golaszewski, Brian Norris, Chuanhong Guo, Conor Dooley,
Damien Le Moal, Daniel Lezcano, Dmitry Torokhov,
Emil Renner Berthing, Eric Dumazet, Florian Fainelli,
Guenter Roeck, Hartley Sweeten, Heiko Stuebner, Hitomi Hasegawa,
Jakub Kicinski, Jaroslav Kysela, Jean Delvare, Joel Stanley,
Jonathan Cameron, Krzysztof Kozlowski, Le Moal, Liam Girdwood,
Liang Yang, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, linux-gpio, linux-ide, linux-input,
linux-kernel, linux-mtd, linux-pm, linux-pwm, linux-rtc,
linux-spi, linux-watchdog, netdev, soc
On Mon, Apr 24, 2023 at 11:35 AM Nikita Shubin
<nikita.shubin@maquefel.me> wrote:
> This series aims to convert ep93xx from platform to full device tree support.
>
> Tested on ts7250 64 RAM/128 MiB Nand flash, edb9302.
Neat, I'd say let's merge this for 6.5 once the final rough edges are
off. The DT bindings should be easy to fix.
This is a big patch set and the improvement to the ARM kernel it
brings is great, so I am a bit worried about over-review stalling the
merged. If there start to be nitpicky comments I would prefer that
we merge it and let minor comments and "nice-to-haves" be
addressed in-tree during the development cycle.
I encourage you to use b4 to manage the patch series if you
have time to learn it, it could help you:
https://people.kernel.org/monsieuricon/sending-a-kernel-patch-with-b4-part-1
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
[not found] ` <b5396ef5-3fed-4e98-8f37-a9cd4473bddc@sirena.org.uk>
@ 2023-04-26 21:06 ` Linus Walleij
0 siblings, 0 replies; 26+ messages in thread
From: Linus Walleij @ 2023-04-26 21:06 UTC (permalink / raw)
To: Mark Brown
Cc: Nikita Shubin, Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S. Miller, Jonathan Neuschäfer, Russell King (Oracle),
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Arnd Bergmann,
Bartosz Golaszewski, Brian Norris, Chuanhong Guo, Conor Dooley,
Damien Le Moal, Daniel Lezcano, Dmitry Torokhov,
Emil Renner Berthing, Eric Dumazet, Florian Fainelli,
Guenter Roeck, Hartley Sweeten, Heiko Stuebner, Hitomi Hasegawa,
Jakub Kicinski, Jaroslav Kysela, Jean Delvare, Joel Stanley,
Jonathan Cameron, Krzysztof Kozlowski, Le Moal, Liam Girdwood,
Liang Yang, Lukasz Majewski, Lv Ruyi, Masahiro Yamada,
Michael Turquette, Miquel Raynal, Nathan Chancellor,
Nick Desaulniers, Nicolas Saenz Julienne, Olof Johansson,
Paolo Abeni, Qin Jian, Richard Weinberger, Rob Herring,
Robert Jarzmik, Russell King, Sebastian Reichel, Sergey Shtylyov,
Stephen Boyd, Sumanth Korikkar, Sven Peter, Takashi Iwai,
Thierry Reding, Thomas Gleixner, Ulf Hansson, Vasily Gorbik,
Vignesh Raghavendra, Vinod Koul, Walker Chen, Wim Van Sebroeck,
Yinbo Zhu, alsa-devel, devicetree, dmaengine, linux-arm-kernel,
linux-clk, linux-gpio, linux-ide, linux-input, linux-kernel,
linux-mtd, linux-pm, linux-pwm, linux-rtc, linux-spi,
linux-watchdog, netdev, soc
On Wed, Apr 26, 2023 at 11:02 PM Mark Brown <broonie@kernel.org> wrote:
> On Wed, Apr 26, 2023 at 10:56:53PM +0200, Linus Walleij wrote:
>
> > This is a big patch set and the improvement to the ARM kernel it
> > brings is great, so I am a bit worried about over-review stalling the
> > merged. If there start to be nitpicky comments I would prefer that
> > we merge it and let minor comments and "nice-to-haves" be
> > addressed in-tree during the development cycle.
>
> I'm really not enthusiastic about the SPI bindings being merged as-is.
Agree, the bindings are more important than the code IMO,
they tend to get written in stone.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx
2023-04-24 12:34 ` [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx Nikita Shubin
2023-04-24 13:28 ` Rob Herring
@ 2023-04-28 23:15 ` Stephen Boyd
1 sibling, 0 replies; 26+ messages in thread
From: Stephen Boyd @ 2023-04-28 23:15 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin, Rob Herring,
Krzysztof Kozlowski, Michael Turquette, Hartley Sweeten,
devicetree, linux-kernel, linux-clk
Quoting Nikita Shubin (2023-04-24 05:34:27)
> This adds device tree bindings for the Cirrus Logic EP93xx
> clock block used in these SoCs.
>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
> .../devicetree/bindings/arm/ep93xx.yaml | 102 ++++++++++++++++++
> .../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +++++++++
> 2 files changed, 155 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
> create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
>
> diff --git a/Documentation/devicetree/bindings/arm/ep93xx.yaml b/Documentation/devicetree/bindings/arm/ep93xx.yaml
> new file mode 100644
> index 000000000000..de7020f4f356
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/ep93xx.yaml
Why is this in arm/ directory? Isn't it a clock controller?
> @@ -0,0 +1,102 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/ep93xx.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logick EP93xx device tree bindings
> +
> +description: |+
> + The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
> +
> +maintainers:
> + - Hartley Sweeten <hsweeten@visionengravers.com>
> + - Alexander Sverdlin <alexander.sverdlin@gmail.com>
> + - Nikita Shubin <nikita.shubin@maquefel.me>
> +
> +properties:
> + $nodename:
> + const: '/'
> + compatible:
> + oneOf:
> + - description: The TS-7250 is a compact, full-featured Single Board Computer (SBC)
> + based upon the Cirrus EP9302 ARM9 CPU.
> + items:
> + - const: technologic,ts7250
> + - const: liebherr,bk3
> + - const: cirrus,ep9301
> + - const: cirrus,edb9302
> +
> + soc:
> + type: object
> + patternProperties:
> + "^.*syscon@80930000$":
> + type: object
> + properties:
> + compatible:
> + items:
> + - const: cirrus,ep9301-syscon
> + - const: syscon
> + - const: simple-mfd
Is there a reason it needs to be a syscon? Or a simple-mfd?
> + ep9301-reboot:
> + type: object
> + properties:
> + compatible:
> + const: cirrus,ep9301-reboot
> + required:
> + - compatible
> + - reg
> + - '#clock-cells'
> + - ep9301-reboot
> +
> + "^.*timer@80810000$":
> + type: object
> + properties:
> + compatible:
> + const: cirrus,ep9301-timer
> +
> + required:
> + - syscon@80930000
> + - timer@80810000
> +
> +required:
> + - compatible
> + - soc
> +
> +additionalProperties: true
> +
> +examples:
> + - |
> + / {
> + compatible = "technologic,ts7250", "cirrus,ep9301";
> + model = "TS-7250 SBC";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + compatible = "simple-bus";
> +
> + syscon: syscon@80930000 {
> + compatible = "cirrus,ep9301-syscon",
> + "syscon", "simple-mfd";
> + reg = <0x80930000 0x1000>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> +
> + ep9301-reboot {
> + compatible = "cirrus,ep9301-reboot";
> + };
> + };
The example should only be the clock controller node. No soc node, or
root node.
> +
> + timer: timer@80810000 {
> + compatible = "cirrus,ep9301-timer";
> + reg = <0x80810000 0x100>;
> + interrupt-parent = <&vic1>;
> + interrupts = <19>;
> + };
> + };
> + };
> +
> +...
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
2023-04-24 12:01 ` Christophe JAILLET
2023-04-24 17:17 ` kernel test robot
@ 2023-04-29 0:58 ` Stephen Boyd
2023-05-15 13:31 ` Nikita Shubin
2 siblings, 1 reply; 26+ messages in thread
From: Stephen Boyd @ 2023-04-29 0:58 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, linux-kernel, linux-clk
Quoting Nikita Shubin (2023-04-24 05:34:28)
> This is a rewrite of EP93xx timer driver in
> arch/arm/mach-ep93xx/clock.c trying to do everything
> the device tree way:
>
> - convert to syscon driver
> - provide clock acces via of
But clkdev is still around?
>
> Co-developed-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
>
> Notes:
> rfc->v0
> Linus Walleij:
> - renamed all __underscore
>
> Alexander Sverdlin:
> - "Logick" -> "Logic"
>
> Changes by Alexander Sverdlin:
> - remove pr_info
> - DIV_ROUND_UP_ULL -> DIV_ROUND_CLOSEST
> - fix zeroing bitfield in ep93xx_div_set_rate
> - add sanity check for EP93XX_SYSCON_CHIPID_ID
> - use bit index for DMA clock's
> - ep93xx_clk_register_gate() takes bit index, not mask
> - remove redundant define
> - use DIV_ROUND_CLOSEST() everywhere to achieve frequencies closer to those
> requested
> - Add the forgotten configuration from the deleted
> arch/arm/mach-ep93xx/core.c
>
> drivers/clk/Kconfig | 8 +
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-ep93xx.c | 880 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 889 insertions(+)
> create mode 100644 drivers/clk/clk-ep93xx.c
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 1eef05bb1f99..d3ad975b688e 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -436,6 +436,14 @@ config COMMON_CLK_K210
> help
> Support for the Canaan Kendryte K210 RISC-V SoC clocks.
>
> +config COMMON_CLK_EP93XX
Keep this sorted based on Kconfig symbol.
> + bool "Clock driver for Cirrus Logic ep93xx SoC"
> + depends on ARCH_EP93XX || COMPILE_TEST
> + select MFD_SYSCON
> + select REGMAP
> + help
> + This driver supports the SoC clocks on the Cirrus Logic ep93xx.
> +
> source "drivers/clk/actions/Kconfig"
> source "drivers/clk/analogbits/Kconfig"
> source "drivers/clk/baikal-t1/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index e3ca0d058a25..deec25ffd004 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
> obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
> obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
> obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
> +obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
> obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
> obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
> obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
> diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c
> new file mode 100644
> index 000000000000..e5913fc4c39b
> --- /dev/null
> +++ b/drivers/clk/clk-ep93xx.c
> @@ -0,0 +1,880 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Clock control for Cirrus EP93xx chips.
> + * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
> + *
> + * Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
> + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
> + */
> +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/soc/cirrus/ep93xx.h>
> +#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
> +
> +#include <asm/div64.h>
> +
> +#define EP93XX_EXT_CLK_RATE 14745600
> +#define EP93XX_EXT_RTC_RATE 32768
> +
> +#define EP93XX_SYSCON_POWER_STATE 0x00
> +#define EP93XX_SYSCON_PWRCNT 0x04
> +#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
> +#define EP93XX_SYSCON_PWRCNT_USH_EN 28
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
> +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
> +#define EP93XX_SYSCON_CLKSET1 0x20
> +#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
> +#define EP93XX_SYSCON_CLKSET2 0x24
> +#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
> +#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
> +#define EP93XX_SYSCON_DEVCFG 0x80
> +#define EP93XX_SYSCON_DEVCFG_U3EN 24
> +#define EP93XX_SYSCON_DEVCFG_U2EN 20
> +#define EP93XX_SYSCON_DEVCFG_U1EN 18
> +#define EP93XX_SYSCON_VIDCLKDIV 0x84
> +#define EP93XX_SYSCON_CLKDIV_ENABLE 15
> +#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
> +#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
> +#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
> +#define EP93XX_SYSCON_I2SCLKDIV 0x8c
> +#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
> +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
> +#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
> +#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
> +#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
> +#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
> +#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
> +#define EP93XX_SYSCON_CHIPID 0x94
> +#define EP93XX_SYSCON_CHIPID_ID 0x9213
> +
> +static DEFINE_SPINLOCK(clk_lock);
This name is not unique. Please make it unique by prefixing with ep93xx.
> +static struct regmap *ep93xx_map;
Do these need to be static globals? Doing a runtime allocation reduces
the size overhead for kernel images that don't have this hardware but
compile in this driver, i.e. distros.
> +#define ep93xx_regmap_read(reg, val) regmap_read(ep93xx_map, reg, val)
> +
> +/* Keeps track of all clocks */
> +static struct clk_hw_onecell_data *ep93xx_clk_data;
Same static global question.
> +
> +static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
> +static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
> +static char pclk_divisors[] = { 1, 2, 4, 8 };
> +
> +static char adc_divisors[] = { 16, 4 };
> +static char sclk_divisors[] = { 2, 4 };
> +static char lrclk_divisors[] = { 32, 64, 128 };
const?
> +
> +static const char * const mux_parents[] = {
> + "xtali",
> + "pll1",
> + "pll2"
> +};
> +
> +/*
> + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
> + */
> +static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word)
u64 rate
> +{
> + int i;
> +
> + rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
> + rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
> + do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
> + for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
> + rate >>= 1;
> +
> + return (unsigned long)rate;
Drop useless cast.
> +}
> +
> +struct clk_psc {
> + struct clk_hw hw;
> + unsigned int reg;
> + u8 bit_idx;
> + u32 mask;
> + u8 shift;
> + u8 width;
> + char *div;
> + u8 num_div;
> + spinlock_t *lock;
> +};
> +
> +#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
> +
> +static int ep93xx_clk_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> +
> + return (val & BIT(psc->bit_idx)) ? 1 : 0;
> +}
> +
> +static int ep93xx_clk_enable(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val |= BIT(psc->bit_idx);
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +
> + return 0;
> +}
> +
> +static void ep93xx_clk_disable(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~BIT(psc->bit_idx);
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +}
> +
> +static const struct clk_ops clk_ep93xx_gate_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> +};
> +
> +static struct clk_hw *ep93xx_clk_register_gate(const char *name,
> + const char *parent_name,
> + unsigned int reg,
> + u8 bit_idx)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &clk_ep93xx_gate_ops;
> + init.flags = CLK_SET_RATE_PARENT;
> + init.parent_names = (parent_name ? &parent_name : NULL);
> + init.num_parents = (parent_name ? 1 : 0);
Please use parent_data or parent_hw instead.
> +
> + psc->reg = reg;
> + psc->bit_idx = bit_idx;
> + psc->hw.init = &init;
> + psc->lock = &clk_lock;
> +
> + clk = clk_register(NULL, &psc->hw);
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
> + return 0;
> +
> + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
> + return 1;
> +
> + return 2;
> +}
> +
> +static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long flags = 0;
> + u32 val;
> +
> + if (index >= ARRAY_SIZE(mux_parents))
> + return -EINVAL;
> +
> + if (psc->lock)
Can you simply lock all the time?
> + spin_lock_irqsave(psc->lock, flags);
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
> +
> + if (index != 0) {
> + val |= EP93XX_SYSCON_CLKDIV_ESEL;
> + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
> + }
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + if (psc->lock)
> + spin_unlock_irqrestore(psc->lock, flags);
> +
> + return 0;
> +}
> +
> +static bool is_best(unsigned long rate, unsigned long now,
> + unsigned long best)
> +{
> + return abs(rate - now) < abs(rate - best);
> +}
> +
> +static int ep93xx_mux_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + unsigned long rate = req->rate;
> + struct clk *parent_best = NULL;
> + unsigned long parent_rate;
> + unsigned long best_rate = 0, actual_rate, mclk_rate;
> + unsigned long parent_rate_best;
> + int div, pdiv;
> + int i;
> +
> + /*
> + * Try the two pll's and the external clock
> + * Because the valid predividers are 2, 2.5 and 3, we multiply
> + * all the clocks by 2 to avoid floating point math.
> + *
> + * This is based on the algorithm in the ep93xx raster guide:
> + * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
> + *
> + */
> + for (i = 0; i < ARRAY_SIZE(mux_parents); i++) {
> + struct clk *parent = clk_get_sys(mux_parents[i], NULL);
The possible parents can be had with clk_hw_get_parent_by_index(). Use
that so you can stop leaking .
> +
> + parent_rate = clk_get_rate(parent);
> + mclk_rate = parent_rate * 2;
The parent_rate is available via clk_hw_get_rate() or by looking at the
clk_rate_request structure 'req' if the parent is the current parent, or
by calling clk_hw_round_rate() or the poorly named
__clk_determine_rate(). In this case it looks like the parents aren't
expected to change rate, so clk_hw_get_rate() will work.
> +
> + /* Try each predivider value */
> + for (pdiv = 4; pdiv <= 6; pdiv++) {
> + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> + if (div < 1 || div > 127)
> + continue;
> +
> + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
> +
> + if (is_best(rate, actual_rate, best_rate)) {
> + best_rate = actual_rate;
> + parent_rate_best = parent_rate;
> + parent_best = parent;
> + }
> + }
> + }
> +
> + if (!parent_best)
> + return -EINVAL;
> +
> + req->best_parent_rate = parent_rate_best;
> + req->best_parent_hw = __clk_get_hw(parent_best);
> + req->rate = best_rate;
> +
> + return 0;
> +}
> +
> +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long rate = 0;
> + u32 val;
> + int pdiv, div;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
> + div = val & 0x7f;
> + if (div > 0)
> + rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
> +
> + return rate;
> +}
> +
> +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + int pdiv, div, npdiv, ndiv;
> + unsigned long actual_rate, mclk_rate, rate_err = -1;
> + int found = 0;
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + mclk_rate = parent_rate * 2;
> +
> + for (pdiv = 4; pdiv <= 6; pdiv++) {
> + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> + if (div < 1 || div > 127)
> + continue;
> +
> + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
> +
> + if (!found || abs(actual_rate - rate) < rate_err) {
> + npdiv = pdiv - 3;
> + ndiv = div;
> + rate_err = abs(actual_rate - rate);
> + found = 1;
> + }
> + }
> +
> + if (!found)
> + return -EINVAL;
> +
> + /* Clear old dividers */
> + val &= ~0x37f;
> +
> + /* Set the new pdiv and div bits for the new clock rate */
> + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops clk_ddiv_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> + .get_parent = ep93xx_mux_get_parent,
> + .set_parent = ep93xx_mux_set_parent_lock,
> + .determine_rate = ep93xx_mux_determine_rate,
> + .recalc_rate = ep93xx_ddiv_recalc_rate,
> + .set_rate = ep93xx_ddiv_set_rate,
> +};
> +
> +static struct clk_hw *clk_hw_register_ddiv(const char *name,
> + unsigned int reg,
> + u8 bit_idx)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &clk_ddiv_ops;
> + init.flags = 0;
> + init.parent_names = mux_parents;
> + init.num_parents = ARRAY_SIZE(mux_parents);
> +
> + psc->reg = reg;
> + psc->bit_idx = bit_idx;
> + psc->lock = &clk_lock;
> + psc->hw.init = &init;
> +
> + clk = clk_register(NULL, &psc->hw);
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> + u8 index;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + index = (val & psc->mask) >> psc->shift;
> + if (index > psc->num_div)
> + return 0;
> +
> + return DIV_ROUND_CLOSEST(parent_rate, psc->div[index]);
> +}
> +
> +static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long best = 0, now;
> + bool assigned = false;
> + int i;
> +
> + for (i = 0; i < psc->num_div; i++) {
> + if ((rate * psc->div[i]) == *parent_rate)
> + return rate;
> +
> + now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
> +
> + if (!assigned || is_best(rate, now, best))
> + best = now;
> + assigned = true;
> + }
> +
> + return best;
> +}
> +
> +static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> + int i;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~psc->mask;
> + for (i = 0; i < psc->num_div; i++)
> + if (rate == DIV_ROUND_CLOSEST(parent_rate, psc->div[i])) {
> + val |= i << psc->shift;
> + break;
> + }
> +
> + if (i == psc->num_div)
> + return -EINVAL;
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops ep93xx_div_ops = {
> + .enable = ep93xx_clk_enable,
> + .disable = ep93xx_clk_disable,
> + .is_enabled = ep93xx_clk_is_enabled,
> + .recalc_rate = ep93xx_div_recalc_rate,
> + .round_rate = ep93xx_div_round_rate,
> + .set_rate = ep93xx_div_set_rate,
> +};
> +
> +static struct clk_hw *clk_hw_register_div(const char *name,
> + const char *parent_name,
> + unsigned int reg,
> + u8 enable_bit,
> + u8 shift,
> + u8 width,
> + char *clk_divisors,
> + u8 num_div)
> +{
> + struct clk_init_data init;
> + struct clk_psc *psc;
> + struct clk *clk;
> +
> + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> + if (!psc)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &ep93xx_div_ops;
> + init.flags = 0;
> + init.parent_names = (parent_name ? &parent_name : NULL);
> + init.num_parents = 1;
> +
> + psc->reg = reg;
> + psc->bit_idx = enable_bit;
> + psc->mask = GENMASK(shift + width - 1, shift);
> + psc->shift = shift;
> + psc->div = clk_divisors;
> + psc->num_div = num_div;
> + psc->lock = &clk_lock;
> + psc->hw.init = &init;
> +
> + clk = clk_register(NULL, &psc->hw);
Use clk_hw_register()
> + if (IS_ERR(clk)) {
> + kfree(psc);
> + return ERR_CAST(clk);
> + }
> +
> + return &psc->hw;
> +}
> +
> +struct ep93xx_gate {
> + unsigned int idx;
> + unsigned int bit;
> + const char *dev_id;
> + const char *con_id;
> +};
> +
> +static struct ep93xx_gate ep93xx_uarts[] = {
> + {EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL},
> + {EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL},
> + {EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL},
> +};
> +
> +static void ep93xx_uart_clock_init(void)
> +{
> + unsigned int i;
> + struct clk_hw *hw;
> + u32 val;
> + unsigned int clk_uart_div;
> +
> + ep93xx_regmap_read(EP93XX_SYSCON_PWRCNT, &val);
> + if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
> + clk_uart_div = 1;
> + else
> + clk_uart_div = 2;
> +
> + hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div);
> + ep93xx_clk_data->hws[EP93XX_CLK_UART] = hw;
> +
> + /* parenting uart gate clocks to uart clock */
> + for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
> + hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id,
> + "uart",
> + EP93XX_SYSCON_DEVCFG,
> + ep93xx_uarts[i].bit);
> +
> + ep93xx_clk_data->hws[ep93xx_uarts[i].idx] = hw;
> + }
> +}
> +
> +static struct ep93xx_gate ep93xx_dmas[] = {
const?
> + {EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"},
Put space after { and before }
> + {EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"},
> + {EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"},
> + {EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"},
> + {EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"},
> + {EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"},
> + {EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"},
> + {EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"},
> + {EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"},
> + {EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"},
> + {EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"},
> + {EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"},
> +};
> +
> +static void ep93xx_dma_clock_init(void __iomem *base)
> +{
> + int i;
> + struct clk_hw *hw;
> + int ret;
> +
> + for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
> + hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id,
> + "hclk", 0,
> + base + EP93XX_SYSCON_PWRCNT,
> + ep93xx_dmas[i].bit,
> + 0,
> + &clk_lock);
> +
> + ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL);
> + if (ret) {
> + pr_err("%s: failed to register lookup %s\n",
> + __func__, ep93xx_dmas[i].con_id);
> + continue;
> + }
> +
> + ep93xx_clk_data->hws[ep93xx_dmas[i].idx] = hw;
> + }
> +}
> +
> +static int ep93xx_clk_probe(struct platform_device *pdev)
> +{
> + void __iomem *base;
> + unsigned int clk_usb_div;
> + unsigned long clk_spi_div;
> + struct clk_hw *hw;
> + struct device *dev = &pdev->dev;
> + u32 value;
> + struct resource *res;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> + clk_usb_div = (((value >> 28) & 0xf) + 1);
> + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
> + hw = clk_hw_register_gate(NULL, "ohci-platform",
> + "usb_clk", 0,
> + base + EP93XX_SYSCON_PWRCNT,
> + EP93XX_SYSCON_PWRCNT_USH_EN,
> + 0,
> + &clk_lock);
> + clk_hw_register_clkdev(hw, NULL, "ohci-platform");
> + ep93xx_clk_data->hws[EP93XX_CLK_USB] = hw;
> +
> + /*
> + * EP93xx SSP clock rate was doubled in version E2. For more information
> + * see:
> + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> + */
> + clk_spi_div = 1;
> + if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> + clk_spi_div = 2;
> + hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div);
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0");
> + ep93xx_clk_data->hws[EP93XX_CLK_SPI] = hw;
> +
> + /* pwm clock */
> + hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1);
> + clk_hw_register_clkdev(hw, "pwm_clk", NULL);
> + ep93xx_clk_data->hws[EP93XX_CLK_PWM] = hw;
> +
> + ep93xx_uart_clock_init();
> +
> + /* touchscreen/adc clock */
> + hw = clk_hw_register_div("ep93xx-adc",
> + "xtali",
> + EP93XX_SYSCON_KEYTCHCLKDIV,
> + EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
> + EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
> + 1,
> + adc_divisors,
> + ARRAY_SIZE(adc_divisors));
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-adc");
> + ep93xx_clk_data->hws[EP93XX_CLK_ADC] = hw;
> +
> + /* keypad clock */
> + hw = clk_hw_register_div("ep93xx-keypad",
> + "xtali",
> + EP93XX_SYSCON_KEYTCHCLKDIV,
> + EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
> + EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
> + 1,
> + adc_divisors,
> + ARRAY_SIZE(adc_divisors));
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad");
> + ep93xx_clk_data->hws[EP93XX_CLK_KEYPAD] = hw;
> +
> + /* On reset PDIV and VDIV is set to zero, while PDIV zero
The /* is on a line by itself.
> + * means clock disable, VDIV shouldn't be zero.
> + * So i set both dividers to minimum.
> + */
> + /* ENA - Enable CLK divider. */
> + /* PDIV - 00 - Disable clock */
> + /* VDIV - at least 2 */
> + /* Check and enable video clk registers */
> + ep93xx_regmap_read(EP93XX_SYSCON_VIDCLKDIV, &value);
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV);
> +
> + /* check and enable i2s clk registers */
> + ep93xx_regmap_read(EP93XX_SYSCON_I2SCLKDIV, &value);
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> + /*
> + * Override the SAI_MSTR_CLK_CFG from the I2S block and use the
> + * I2SClkDiv Register settings. LRCLK transitions on the falling SCLK
> + * edge.
> + */
> + value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
> + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV);
> +
> + /* video clk */
> + hw = clk_hw_register_ddiv("ep93xx-fb",
> + EP93XX_SYSCON_VIDCLKDIV,
> + EP93XX_SYSCON_CLKDIV_ENABLE);
> +
> + clk_hw_register_clkdev(hw, NULL, "ep93xx-fb");
> + ep93xx_clk_data->hws[EP93XX_CLK_VIDEO] = hw;
> +
> + /* i2s clk */
> + hw = clk_hw_register_ddiv("mclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_CLKDIV_ENABLE);
> +
> + clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_MCLK] = hw;
> +
> + /* i2s sclk */
> +#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16
> +#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1
> + hw = clk_hw_register_div("sclk",
> + "mclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_I2SCLKDIV_SENA,
> + EP93XX_I2SCLKDIV_SDIV_SHIFT,
> + EP93XX_I2SCLKDIV_SDIV_WIDTH,
> + sclk_divisors,
> + ARRAY_SIZE(sclk_divisors));
> +
> + clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_SCLK] = hw;
> +
> + /* i2s lrclk */
> +#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17
> +#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 2
Please just inline these defines as they're only used on place.
> + hw = clk_hw_register_div("lrclk",
> + "sclk",
> + EP93XX_SYSCON_I2SCLKDIV,
> + EP93XX_SYSCON_I2SCLKDIV_SENA,
> + EP93XX_I2SCLKDIV_LRDIV32_SHIFT,
> + EP93XX_I2SCLKDIV_LRDIV32_WIDTH,
> + lrclk_divisors,
> + ARRAY_SIZE(lrclk_divisors));
> +
> + clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s");
> + ep93xx_clk_data->hws[EP93XX_CLK_I2S_LRCLK] = hw;
> +
> + /* IrDa clk uses same pattern but no init code presents in original clock driver */
> + return 0;
> +}
> +
> +static const struct of_device_id ep93xx_clk_dt_ids[] = {
> + { .compatible = "cirrus,ep9301-syscon", },
> + { /* sentinel */ },
> +};
> +
> +static struct platform_driver ep93xx_clk_driver = {
> + .probe = ep93xx_clk_probe,
> + .driver = {
> + .name = "ep93xx-clk",
> + .of_match_table = ep93xx_clk_dt_ids,
> + .suppress_bind_attrs = true,
> + },
> +};
> +builtin_platform_driver(ep93xx_clk_driver);
> +
> +static void __init ep93xx_clock_init(struct device_node *np)
> +{
> + void __iomem *base;
> + int i;
> + int ret;
> + u32 value;
> + struct clk_hw *hw;
> + unsigned long clk_pll1_rate;
> + unsigned long clk_f_rate;
> + unsigned long clk_h_rate;
> + unsigned long clk_p_rate;
> + unsigned long clk_pll2_rate;
> + unsigned int clk_f_div;
> + unsigned int clk_h_div;
> + unsigned int clk_p_div;
> +
> + ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
> + EP93XX_NUM_CLKS),
> + GFP_KERNEL);
> +
> + if (!ep93xx_clk_data)
> + return;
> +
> + /*
> + * This way all clock fetched before the platform device probes,
> + * except those we assign here for early use, will be deferred.
> + */
> + for (i = 0; i < EP93XX_NUM_CLKS; i++)
> + ep93xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
> +
> + base = of_iomap(np, 0);
> + /* Remap the system controller for the exclusive register */
> + if (IS_ERR(base)) {
> + pr_err("failed to map base\n");
> + return;
> + }
> +
> + ep93xx_map = syscon_node_to_regmap(np);
> + if (IS_ERR(ep93xx_map)) {
> + pr_err("no syscon regmap\n");
> + return;
> + }
> +
> + /*
> + * We check that the regmap works on this very first access,
> + * but as this is an MMIO-backed regmap, subsequent regmap
> + * access is not going to fail and we skip error checks from
> + * this point.
> + */
> + ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
> + if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
> + pr_err("failed to read global status register\n");
> + return;
> + }
> +
> + hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE);
Maybe this can be registered from DT itself.
> + clk_hw_register_clkdev(hw, NULL, "xtali");
> +
> + /* Determine the bootloader configured pll1 rate */
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET1, &value);
> + if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
> + clk_pll1_rate = EP93XX_EXT_CLK_RATE;
> + else
> + clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
> +
> + hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate);
And maybe this can be registered from wherever the regmap is created?
> + clk_hw_register_clkdev(hw, NULL, "pll1");
Do you need to use clkdev?
> + ep93xx_clk_data->hws[EP93XX_CLK_PLL1] = hw;
> +
> + /* Initialize the pll1 derived clocks */
> + clk_f_div = fclk_divisors[(value >> 25) & 0x7];
> + clk_h_div = hclk_divisors[(value >> 20) & 0x7];
> + clk_p_div = pclk_divisors[(value >> 18) & 0x3];
> +
> + hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div);
> + clk_f_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_FCLK] = hw;
> + hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div);
> + clk_h_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_HCLK] = hw;
> + hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div);
> + clk_p_rate = clk_get_rate(hw->clk);
> + ep93xx_clk_data->hws[EP93XX_CLK_PCLK] = hw;
Try to not use clk consumer APIs from a clk provider. In this case, it
looks like some debug message, so just drop these clk_get_rate() calls
and the associated printks.
> +
> + clk_hw_register_clkdev(hw, "apb_pclk", NULL);
> +
> + ep93xx_dma_clock_init(base);
Does some interrupt or timer driver use dma? Why are these registered
early?
> +
> + /* Determine the bootloader configured pll2 rate */
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
> + clk_pll2_rate = EP93XX_EXT_CLK_RATE;
> + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
> + clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
> + else
> + clk_pll2_rate = 0;
> +
> + hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate);
Instead of registering a fixed rate clk here you can implemented
recalc_rate and look at the regmap value.
> + ep93xx_clk_data->hws[EP93XX_CLK_PLL2] = hw;
> + clk_hw_register_clkdev(hw, NULL, "pll2");
> +
> + ep93xx_clk_data->num = EP93XX_NUM_CLKS;
> + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ep93xx_clk_data);
> +
> + pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
> + clk_pll1_rate / 1000000, clk_pll2_rate / 1000000);
> + pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
> + clk_f_rate / 1000000, clk_h_rate / 1000000,
> + clk_p_rate / 1000000);
> +}
> +CLK_OF_DECLARE_DRIVER(ep93xx_cc, "cirrus,ep9301-syscon", ep93xx_clock_init);
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-29 0:58 ` Stephen Boyd
@ 2023-05-15 13:31 ` Nikita Shubin
2023-06-13 20:44 ` Stephen Boyd
0 siblings, 1 reply; 26+ messages in thread
From: Nikita Shubin @ 2023-05-15 13:31 UTC (permalink / raw)
To: Stephen Boyd
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, linux-kernel, linux-clk
Hello Stephen!
Thank you for your review.
Acknowledged all remarks, however, i didn't fully understood some of
the requirements:
> And maybe this can be registered from wherever the regmap is created?
Are you suggesting that all clock from init, i.e. "pll1", "pll2",
"hclk", "fclk", "pclk"
Should be moved to SoC driver instead:
https://lore.kernel.org/all/20230424123522.18302-3-nikita.shubin@maquefel.me/
?
> Does some interrupt or timer driver use dma? Why are these registered
> early?
ep93xx_dma uses subsys_initcall(ep93xx_dma_module_init)
https://elixir.bootlin.com/linux/v6.3.2/source/drivers/dma/ep93xx_dma.c#L1430
I can move clk to using arch_initcall and move all stuff to probe, i
think...
> Why is this in arm/ directory? Isn't it a clock controller?
ep93xx clocks, reboot, pinctrl use syscon regmap and some special
functions from SoC, i.e. "Syscon Software Lock Register" - so we are
able to write to some registers only after writing some magik value
there.
So all above use regmap from SoC.
Should make a separate clock controller like one i did for pinctrl ?
Then it should look like:
syscon@80930000 {
compatible = "cirrus,ep9301-syscon",
"syscon", "simple-mfd";
reg = <0x80930000 0x1000>;
#reset-cells = <1>;
clocks {
xtali: oscillator {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <14745600>;
};
};
clock-controller {
#clock-cells = <1>;
compatible = "cirrus,ep9301-clk";
clocks = <&xtali>;
};
};
Or even simply:
clocks {
xtali: oscillator {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <14745600>;
};
};
clock-controller {
#clock-cells = <1>;
compatible = "cirrus,ep9301-clk";
clocks = <&xtali>;
};
On Fri, 2023-04-28 at 17:58 -0700, Stephen Boyd wrote:
> Quoting Nikita Shubin (2023-04-24 05:34:28)
> > This is a rewrite of EP93xx timer driver in
> > arch/arm/mach-ep93xx/clock.c trying to do everything
> > the device tree way:
> >
> > - convert to syscon driver
> > - provide clock acces via of
>
> But clkdev is still around?
>
> >
> > Co-developed-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> > Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> > Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> > ---
> >
> > Notes:
> > rfc->v0
> > Linus Walleij:
> > - renamed all __underscore
> >
> > Alexander Sverdlin:
> > - "Logick" -> "Logic"
> >
> > Changes by Alexander Sverdlin:
> > - remove pr_info
> > - DIV_ROUND_UP_ULL -> DIV_ROUND_CLOSEST
> > - fix zeroing bitfield in ep93xx_div_set_rate
> > - add sanity check for EP93XX_SYSCON_CHIPID_ID
> > - use bit index for DMA clock's
> > - ep93xx_clk_register_gate() takes bit index, not mask
> > - remove redundant define
> > - use DIV_ROUND_CLOSEST() everywhere to achieve frequencies
> > closer to those
> > requested
> > - Add the forgotten configuration from the deleted
> > arch/arm/mach-ep93xx/core.c
> >
> > drivers/clk/Kconfig | 8 +
> > drivers/clk/Makefile | 1 +
> > drivers/clk/clk-ep93xx.c | 880
> > +++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 889 insertions(+)
> > create mode 100644 drivers/clk/clk-ep93xx.c
> >
> > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> > index 1eef05bb1f99..d3ad975b688e 100644
> > --- a/drivers/clk/Kconfig
> > +++ b/drivers/clk/Kconfig
> > @@ -436,6 +436,14 @@ config COMMON_CLK_K210
> > help
> > Support for the Canaan Kendryte K210 RISC-V SoC clocks.
> >
> > +config COMMON_CLK_EP93XX
>
> Keep this sorted based on Kconfig symbol.
>
> > + bool "Clock driver for Cirrus Logic ep93xx SoC"
> > + depends on ARCH_EP93XX || COMPILE_TEST
> > + select MFD_SYSCON
> > + select REGMAP
> > + help
> > + This driver supports the SoC clocks on the Cirrus Logic
> > ep93xx.
> > +
> > source "drivers/clk/actions/Kconfig"
> > source "drivers/clk/analogbits/Kconfig"
> > source "drivers/clk/baikal-t1/Kconfig"
> > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> > index e3ca0d058a25..deec25ffd004 100644
> > --- a/drivers/clk/Makefile
> > +++ b/drivers/clk/Makefile
> > @@ -29,6 +29,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-
> > cdce706.o
> > obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
> > obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
> > obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
> > +obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
> > obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
> > obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
> > obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
> > diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c
> > new file mode 100644
> > index 000000000000..e5913fc4c39b
> > --- /dev/null
> > +++ b/drivers/clk/clk-ep93xx.c
> > @@ -0,0 +1,880 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Clock control for Cirrus EP93xx chips.
> > + * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
> > + *
> > + * Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
> > + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
> > + */
> > +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/clk.h>
> > +#include <linux/err.h>
> > +#include <linux/module.h>
> > +#include <linux/string.h>
> > +#include <linux/io.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/soc/cirrus/ep93xx.h>
> > +#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
> > +
> > +#include <asm/div64.h>
> > +
> > +#define EP93XX_EXT_CLK_RATE 14745600
> > +#define EP93XX_EXT_RTC_RATE 32768
> > +
> > +#define EP93XX_SYSCON_POWER_STATE 0x00
> > +#define EP93XX_SYSCON_PWRCNT 0x04
> > +#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
> > +#define EP93XX_SYSCON_PWRCNT_USH_EN 28
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
> > +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
> > +#define EP93XX_SYSCON_CLKSET1 0x20
> > +#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
> > +#define EP93XX_SYSCON_CLKSET2 0x24
> > +#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
> > +#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
> > +#define EP93XX_SYSCON_DEVCFG 0x80
> > +#define EP93XX_SYSCON_DEVCFG_U3EN 24
> > +#define EP93XX_SYSCON_DEVCFG_U2EN 20
> > +#define EP93XX_SYSCON_DEVCFG_U1EN 18
> > +#define EP93XX_SYSCON_VIDCLKDIV 0x84
> > +#define EP93XX_SYSCON_CLKDIV_ENABLE 15
> > +#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
> > +#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
> > +#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
> > +#define EP93XX_SYSCON_I2SCLKDIV 0x8c
> > +#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
> > +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
> > +#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
> > +#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
> > +#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
> > +#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
> > +#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
> > +#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
> > +#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
> > +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
> > +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
> > +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
> > +#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
> > +#define EP93XX_SYSCON_CHIPID 0x94
> > +#define EP93XX_SYSCON_CHIPID_ID 0x9213
> > +
> > +static DEFINE_SPINLOCK(clk_lock);
>
> This name is not unique. Please make it unique by prefixing with
> ep93xx.
>
> > +static struct regmap *ep93xx_map;
>
> Do these need to be static globals? Doing a runtime allocation
> reduces
> the size overhead for kernel images that don't have this hardware but
> compile in this driver, i.e. distros.
>
> > +#define ep93xx_regmap_read(reg, val) regmap_read(ep93xx_map, reg,
> > val)
> > +
> > +/* Keeps track of all clocks */
> > +static struct clk_hw_onecell_data *ep93xx_clk_data;
>
> Same static global question.
>
> > +
> > +static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
> > +static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
> > +static char pclk_divisors[] = { 1, 2, 4, 8 };
> > +
> > +static char adc_divisors[] = { 16, 4 };
> > +static char sclk_divisors[] = { 2, 4 };
> > +static char lrclk_divisors[] = { 32, 64, 128 };
>
> const?
>
> > +
> > +static const char * const mux_parents[] = {
> > + "xtali",
> > + "pll1",
> > + "pll2"
> > +};
> > +
> > +/*
> > + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD +
> > 1) / 2^PS
> > + */
> > +static unsigned long calc_pll_rate(unsigned long long rate, u32
> > config_word)
>
> u64 rate
>
> > +{
> > + int i;
> > +
> > + rate *= ((config_word >> 11) & 0x1f) + 1; /*
> > X1FBD */
> > + rate *= ((config_word >> 5) & 0x3f) + 1; /*
> > X2FBD */
> > + do_div(rate, (config_word & 0x1f) + 1); /*
> > X2IPD */
> > + for (i = 0; i < ((config_word >> 16) & 3); i++) /*
> > PS */
> > + rate >>= 1;
> > +
> > + return (unsigned long)rate;
>
> Drop useless cast.
>
> > +}
> > +
> > +struct clk_psc {
> > + struct clk_hw hw;
> > + unsigned int reg;
> > + u8 bit_idx;
> > + u32 mask;
> > + u8 shift;
> > + u8 width;
> > + char *div;
> > + u8 num_div;
> > + spinlock_t *lock;
> > +};
> > +
> > +#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
> > +
> > +static int ep93xx_clk_is_enabled(struct clk_hw *hw)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + u32 val;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > +
> > + return (val & BIT(psc->bit_idx)) ? 1 : 0;
> > +}
> > +
> > +static int ep93xx_clk_enable(struct clk_hw *hw)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long flags = 0;
> > + u32 val;
> > +
> > + if (psc->lock)
> > + spin_lock_irqsave(psc->lock, flags);
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + val |= BIT(psc->bit_idx);
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + if (psc->lock)
> > + spin_unlock_irqrestore(psc->lock, flags);
> > +
> > + return 0;
> > +}
> > +
> > +static void ep93xx_clk_disable(struct clk_hw *hw)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long flags = 0;
> > + u32 val;
> > +
> > + if (psc->lock)
> > + spin_lock_irqsave(psc->lock, flags);
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + val &= ~BIT(psc->bit_idx);
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + if (psc->lock)
> > + spin_unlock_irqrestore(psc->lock, flags);
> > +}
> > +
> > +static const struct clk_ops clk_ep93xx_gate_ops = {
> > + .enable = ep93xx_clk_enable,
> > + .disable = ep93xx_clk_disable,
> > + .is_enabled = ep93xx_clk_is_enabled,
> > +};
> > +
> > +static struct clk_hw *ep93xx_clk_register_gate(const char *name,
> > + const char *parent_name,
> > + unsigned int reg,
> > + u8 bit_idx)
> > +{
> > + struct clk_init_data init;
> > + struct clk_psc *psc;
> > + struct clk *clk;
> > +
> > + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> > + if (!psc)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + init.name = name;
> > + init.ops = &clk_ep93xx_gate_ops;
> > + init.flags = CLK_SET_RATE_PARENT;
> > + init.parent_names = (parent_name ? &parent_name : NULL);
> > + init.num_parents = (parent_name ? 1 : 0);
>
> Please use parent_data or parent_hw instead.
>
> > +
> > + psc->reg = reg;
> > + psc->bit_idx = bit_idx;
> > + psc->hw.init = &init;
> > + psc->lock = &clk_lock;
> > +
> > + clk = clk_register(NULL, &psc->hw);
> > + if (IS_ERR(clk)) {
> > + kfree(psc);
> > + return ERR_CAST(clk);
> > + }
> > +
> > + return &psc->hw;
> > +}
> > +
> > +static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + u32 val;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
> > + return 0;
> > +
> > + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
> > + return 1;
> > +
> > + return 2;
> > +}
> > +
> > +static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long flags = 0;
> > + u32 val;
> > +
> > + if (index >= ARRAY_SIZE(mux_parents))
> > + return -EINVAL;
> > +
> > + if (psc->lock)
>
> Can you simply lock all the time?
>
> > + spin_lock_irqsave(psc->lock, flags);
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL |
> > EP93XX_SYSCON_CLKDIV_PSEL);
> > +
> > + if (index != 0) {
> > + val |= EP93XX_SYSCON_CLKDIV_ESEL;
> > + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
> > + }
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + if (psc->lock)
> > + spin_unlock_irqrestore(psc->lock, flags);
> > +
> > + return 0;
> > +}
> > +
> > +static bool is_best(unsigned long rate, unsigned long now,
> > + unsigned long best)
> > +{
> > + return abs(rate - now) < abs(rate - best);
> > +}
> > +
> > +static int ep93xx_mux_determine_rate(struct clk_hw *hw,
> > + struct clk_rate_request *req)
> > +{
> > + unsigned long rate = req->rate;
> > + struct clk *parent_best = NULL;
> > + unsigned long parent_rate;
> > + unsigned long best_rate = 0, actual_rate, mclk_rate;
> > + unsigned long parent_rate_best;
> > + int div, pdiv;
> > + int i;
> > +
> > + /*
> > + * Try the two pll's and the external clock
> > + * Because the valid predividers are 2, 2.5 and 3, we
> > multiply
> > + * all the clocks by 2 to avoid floating point math.
> > + *
> > + * This is based on the algorithm in the ep93xx raster
> > guide:
> > + * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
> > + *
> > + */
> > + for (i = 0; i < ARRAY_SIZE(mux_parents); i++) {
> > + struct clk *parent = clk_get_sys(mux_parents[i],
> > NULL);
>
> The possible parents can be had with clk_hw_get_parent_by_index().
> Use
> that so you can stop leaking .
>
> > +
> > + parent_rate = clk_get_rate(parent);
> > + mclk_rate = parent_rate * 2;
>
> The parent_rate is available via clk_hw_get_rate() or by looking at
> the
> clk_rate_request structure 'req' if the parent is the current parent,
> or
> by calling clk_hw_round_rate() or the poorly named
> __clk_determine_rate(). In this case it looks like the parents aren't
> expected to change rate, so clk_hw_get_rate() will work.
>
> > +
> > + /* Try each predivider value */
> > + for (pdiv = 4; pdiv <= 6; pdiv++) {
> > + div = DIV_ROUND_CLOSEST(mclk_rate, rate *
> > pdiv);
> > + if (div < 1 || div > 127)
> > + continue;
> > +
> > + actual_rate = DIV_ROUND_CLOSEST(mclk_rate,
> > pdiv * div);
> > +
> > + if (is_best(rate, actual_rate, best_rate))
> > {
> > + best_rate = actual_rate;
> > + parent_rate_best = parent_rate;
> > + parent_best = parent;
> > + }
> > + }
> > + }
> > +
> > + if (!parent_best)
> > + return -EINVAL;
> > +
> > + req->best_parent_rate = parent_rate_best;
> > + req->best_parent_hw = __clk_get_hw(parent_best);
> > + req->rate = best_rate;
> > +
> > + return 0;
> > +}
> > +
> > +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
> > + unsigned long
> > parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long rate = 0;
> > + u32 val;
> > + int pdiv, div;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
> > + div = val & 0x7f;
> > + if (div > 0)
> > + rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv +
> > 3) * div);
> > +
> > + return rate;
> > +}
> > +
> > +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long
> > rate,
> > + unsigned long parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + int pdiv, div, npdiv, ndiv;
> > + unsigned long actual_rate, mclk_rate, rate_err = -1;
> > + int found = 0;
> > + u32 val;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + mclk_rate = parent_rate * 2;
> > +
> > + for (pdiv = 4; pdiv <= 6; pdiv++) {
> > + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> > + if (div < 1 || div > 127)
> > + continue;
> > +
> > + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv *
> > div);
> > +
> > + if (!found || abs(actual_rate - rate) < rate_err) {
> > + npdiv = pdiv - 3;
> > + ndiv = div;
> > + rate_err = abs(actual_rate - rate);
> > + found = 1;
> > + }
> > + }
> > +
> > + if (!found)
> > + return -EINVAL;
> > +
> > + /* Clear old dividers */
> > + val &= ~0x37f;
> > +
> > + /* Set the new pdiv and div bits for the new clock rate */
> > + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct clk_ops clk_ddiv_ops = {
> > + .enable = ep93xx_clk_enable,
> > + .disable = ep93xx_clk_disable,
> > + .is_enabled = ep93xx_clk_is_enabled,
> > + .get_parent = ep93xx_mux_get_parent,
> > + .set_parent = ep93xx_mux_set_parent_lock,
> > + .determine_rate = ep93xx_mux_determine_rate,
> > + .recalc_rate = ep93xx_ddiv_recalc_rate,
> > + .set_rate = ep93xx_ddiv_set_rate,
> > +};
> > +
> > +static struct clk_hw *clk_hw_register_ddiv(const char *name,
> > + unsigned int reg,
> > + u8 bit_idx)
> > +{
> > + struct clk_init_data init;
> > + struct clk_psc *psc;
> > + struct clk *clk;
> > +
> > + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> > + if (!psc)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + init.name = name;
> > + init.ops = &clk_ddiv_ops;
> > + init.flags = 0;
> > + init.parent_names = mux_parents;
> > + init.num_parents = ARRAY_SIZE(mux_parents);
> > +
> > + psc->reg = reg;
> > + psc->bit_idx = bit_idx;
> > + psc->lock = &clk_lock;
> > + psc->hw.init = &init;
> > +
> > + clk = clk_register(NULL, &psc->hw);
> > + if (IS_ERR(clk)) {
> > + kfree(psc);
> > + return ERR_CAST(clk);
> > + }
> > +
> > + return &psc->hw;
> > +}
> > +
> > +static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
> > + unsigned long
> > parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + u32 val;
> > + u8 index;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + index = (val & psc->mask) >> psc->shift;
> > + if (index > psc->num_div)
> > + return 0;
> > +
> > + return DIV_ROUND_CLOSEST(parent_rate, psc->div[index]);
> > +}
> > +
> > +static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long
> > rate,
> > + unsigned long *parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long best = 0, now;
> > + bool assigned = false;
> > + int i;
> > +
> > + for (i = 0; i < psc->num_div; i++) {
> > + if ((rate * psc->div[i]) == *parent_rate)
> > + return rate;
> > +
> > + now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
> > +
> > + if (!assigned || is_best(rate, now, best))
> > + best = now;
> > + assigned = true;
> > + }
> > +
> > + return best;
> > +}
> > +
> > +static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long
> > rate,
> > + unsigned long parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + u32 val;
> > + int i;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + val &= ~psc->mask;
> > + for (i = 0; i < psc->num_div; i++)
> > + if (rate == DIV_ROUND_CLOSEST(parent_rate, psc-
> > >div[i])) {
> > + val |= i << psc->shift;
> > + break;
> > + }
> > +
> > + if (i == psc->num_div)
> > + return -EINVAL;
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct clk_ops ep93xx_div_ops = {
> > + .enable = ep93xx_clk_enable,
> > + .disable = ep93xx_clk_disable,
> > + .is_enabled = ep93xx_clk_is_enabled,
> > + .recalc_rate = ep93xx_div_recalc_rate,
> > + .round_rate = ep93xx_div_round_rate,
> > + .set_rate = ep93xx_div_set_rate,
> > +};
> > +
> > +static struct clk_hw *clk_hw_register_div(const char *name,
> > + const char *parent_name,
> > + unsigned int reg,
> > + u8 enable_bit,
> > + u8 shift,
> > + u8 width,
> > + char *clk_divisors,
> > + u8 num_div)
> > +{
> > + struct clk_init_data init;
> > + struct clk_psc *psc;
> > + struct clk *clk;
> > +
> > + psc = kzalloc(sizeof(*psc), GFP_KERNEL);
> > + if (!psc)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + init.name = name;
> > + init.ops = &ep93xx_div_ops;
> > + init.flags = 0;
> > + init.parent_names = (parent_name ? &parent_name : NULL);
> > + init.num_parents = 1;
> > +
> > + psc->reg = reg;
> > + psc->bit_idx = enable_bit;
> > + psc->mask = GENMASK(shift + width - 1, shift);
> > + psc->shift = shift;
> > + psc->div = clk_divisors;
> > + psc->num_div = num_div;
> > + psc->lock = &clk_lock;
> > + psc->hw.init = &init;
> > +
> > + clk = clk_register(NULL, &psc->hw);
>
> Use clk_hw_register()
>
> > + if (IS_ERR(clk)) {
> > + kfree(psc);
> > + return ERR_CAST(clk);
> > + }
> > +
> > + return &psc->hw;
> > +}
> > +
> > +struct ep93xx_gate {
> > + unsigned int idx;
> > + unsigned int bit;
> > + const char *dev_id;
> > + const char *con_id;
> > +};
> > +
> > +static struct ep93xx_gate ep93xx_uarts[] = {
> > + {EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1",
> > NULL},
> > + {EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2",
> > NULL},
> > + {EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3",
> > NULL},
> > +};
> > +
> > +static void ep93xx_uart_clock_init(void)
> > +{
> > + unsigned int i;
> > + struct clk_hw *hw;
> > + u32 val;
> > + unsigned int clk_uart_div;
> > +
> > + ep93xx_regmap_read(EP93XX_SYSCON_PWRCNT, &val);
> > + if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
> > + clk_uart_div = 1;
> > + else
> > + clk_uart_div = 2;
> > +
> > + hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0,
> > 1, clk_uart_div);
> > + ep93xx_clk_data->hws[EP93XX_CLK_UART] = hw;
> > +
> > + /* parenting uart gate clocks to uart clock */
> > + for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
> > + hw =
> > ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id,
> > + "uart",
> > + EP93XX_SYSCON_DEVCFG,
> > + ep93xx_uarts[i].bit);
> > +
> > + ep93xx_clk_data->hws[ep93xx_uarts[i].idx] = hw;
> > + }
> > +}
> > +
> > +static struct ep93xx_gate ep93xx_dmas[] = {
>
> const?
>
> > + {EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL,
> > "m2p0"},
>
> Put space after { and before }
>
> > + {EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL,
> > "m2p1"},
> > + {EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL,
> > "m2p2"},
> > + {EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL,
> > "m2p3"},
> > + {EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL,
> > "m2p4"},
> > + {EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL,
> > "m2p5"},
> > + {EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL,
> > "m2p6"},
> > + {EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL,
> > "m2p7"},
> > + {EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL,
> > "m2p8"},
> > + {EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL,
> > "m2p9"},
> > + {EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL,
> > "m2m0"},
> > + {EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL,
> > "m2m1"},
> > +};
> > +
> > +static void ep93xx_dma_clock_init(void __iomem *base)
> > +{
> > + int i;
> > + struct clk_hw *hw;
> > + int ret;
> > +
> > + for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
> > + hw = clk_hw_register_gate(NULL,
> > ep93xx_dmas[i].con_id,
> > + "hclk", 0,
> > + base +
> > EP93XX_SYSCON_PWRCNT,
> > + ep93xx_dmas[i].bit,
> > + 0,
> > + &clk_lock);
> > +
> > + ret = clk_hw_register_clkdev(hw,
> > ep93xx_dmas[i].con_id, NULL);
> > + if (ret) {
> > + pr_err("%s: failed to register lookup
> > %s\n",
> > + __func__, ep93xx_dmas[i].con_id);
> > + continue;
> > + }
> > +
> > + ep93xx_clk_data->hws[ep93xx_dmas[i].idx] = hw;
> > + }
> > +}
> > +
> > +static int ep93xx_clk_probe(struct platform_device *pdev)
> > +{
> > + void __iomem *base;
> > + unsigned int clk_usb_div;
> > + unsigned long clk_spi_div;
> > + struct clk_hw *hw;
> > + struct device *dev = &pdev->dev;
> > + u32 value;
> > + struct resource *res;
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + base = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(base))
> > + return PTR_ERR(base);
> > +
> > + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> > + clk_usb_div = (((value >> 28) & 0xf) + 1);
> > + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2",
> > 0, 1, clk_usb_div);
> > + hw = clk_hw_register_gate(NULL, "ohci-platform",
> > + "usb_clk", 0,
> > + base + EP93XX_SYSCON_PWRCNT,
> > + EP93XX_SYSCON_PWRCNT_USH_EN,
> > + 0,
> > + &clk_lock);
> > + clk_hw_register_clkdev(hw, NULL, "ohci-platform");
> > + ep93xx_clk_data->hws[EP93XX_CLK_USB] = hw;
> > +
> > + /*
> > + * EP93xx SSP clock rate was doubled in version E2. For
> > more information
> > + * see:
> > + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> > + */
> > + clk_spi_div = 1;
> > + if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> > + clk_spi_div = 2;
> > + hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0",
> > "xtali", 0, 1, clk_spi_div);
> > + clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0");
> > + ep93xx_clk_data->hws[EP93XX_CLK_SPI] = hw;
> > +
> > + /* pwm clock */
> > + hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali",
> > 0, 1, 1);
> > + clk_hw_register_clkdev(hw, "pwm_clk", NULL);
> > + ep93xx_clk_data->hws[EP93XX_CLK_PWM] = hw;
> > +
> > + ep93xx_uart_clock_init();
> > +
> > + /* touchscreen/adc clock */
> > + hw = clk_hw_register_div("ep93xx-adc",
> > + "xtali",
> > + EP93XX_SYSCON_KEYTCHCLKDIV,
> > + EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
> > + EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
> > + 1,
> > + adc_divisors,
> > + ARRAY_SIZE(adc_divisors));
> > +
> > + clk_hw_register_clkdev(hw, NULL, "ep93xx-adc");
> > + ep93xx_clk_data->hws[EP93XX_CLK_ADC] = hw;
> > +
> > + /* keypad clock */
> > + hw = clk_hw_register_div("ep93xx-keypad",
> > + "xtali",
> > + EP93XX_SYSCON_KEYTCHCLKDIV,
> > + EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
> > + EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
> > + 1,
> > + adc_divisors,
> > + ARRAY_SIZE(adc_divisors));
> > +
> > + clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad");
> > + ep93xx_clk_data->hws[EP93XX_CLK_KEYPAD] = hw;
> > +
> > + /* On reset PDIV and VDIV is set to zero, while PDIV zero
>
> The /* is on a line by itself.
>
> > + * means clock disable, VDIV shouldn't be zero.
> > + * So i set both dividers to minimum.
> > + */
> > + /* ENA - Enable CLK divider. */
> > + /* PDIV - 00 - Disable clock */
> > + /* VDIV - at least 2 */
> > + /* Check and enable video clk registers */
> > + ep93xx_regmap_read(EP93XX_SYSCON_VIDCLKDIV, &value);
> > + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> > + ep93xx_syscon_swlocked_write(value,
> > EP93XX_SYSCON_VIDCLKDIV);
> > +
> > + /* check and enable i2s clk registers */
> > + ep93xx_regmap_read(EP93XX_SYSCON_I2SCLKDIV, &value);
> > + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
> > + /*
> > + * Override the SAI_MSTR_CLK_CFG from the I2S block and use
> > the
> > + * I2SClkDiv Register settings. LRCLK transitions on the
> > falling SCLK
> > + * edge.
> > + */
> > + value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE |
> > EP93XX_SYSCON_I2SCLKDIV_SPOL;
> > + ep93xx_syscon_swlocked_write(value,
> > EP93XX_SYSCON_I2SCLKDIV);
> > +
> > + /* video clk */
> > + hw = clk_hw_register_ddiv("ep93xx-fb",
> > + EP93XX_SYSCON_VIDCLKDIV,
> > + EP93XX_SYSCON_CLKDIV_ENABLE);
> > +
> > + clk_hw_register_clkdev(hw, NULL, "ep93xx-fb");
> > + ep93xx_clk_data->hws[EP93XX_CLK_VIDEO] = hw;
> > +
> > + /* i2s clk */
> > + hw = clk_hw_register_ddiv("mclk",
> > + EP93XX_SYSCON_I2SCLKDIV,
> > + EP93XX_SYSCON_CLKDIV_ENABLE);
> > +
> > + clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s");
> > + ep93xx_clk_data->hws[EP93XX_CLK_I2S_MCLK] = hw;
> > +
> > + /* i2s sclk */
> > +#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16
> > +#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1
> > + hw = clk_hw_register_div("sclk",
> > + "mclk",
> > + EP93XX_SYSCON_I2SCLKDIV,
> > + EP93XX_SYSCON_I2SCLKDIV_SENA,
> > + EP93XX_I2SCLKDIV_SDIV_SHIFT,
> > + EP93XX_I2SCLKDIV_SDIV_WIDTH,
> > + sclk_divisors,
> > + ARRAY_SIZE(sclk_divisors));
> > +
> > + clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s");
> > + ep93xx_clk_data->hws[EP93XX_CLK_I2S_SCLK] = hw;
> > +
> > + /* i2s lrclk */
> > +#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17
> > +#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 2
>
> Please just inline these defines as they're only used on place.
>
> > + hw = clk_hw_register_div("lrclk",
> > + "sclk",
> > + EP93XX_SYSCON_I2SCLKDIV,
> > + EP93XX_SYSCON_I2SCLKDIV_SENA,
> > + EP93XX_I2SCLKDIV_LRDIV32_SHIFT,
> > + EP93XX_I2SCLKDIV_LRDIV32_WIDTH,
> > + lrclk_divisors,
> > + ARRAY_SIZE(lrclk_divisors));
> > +
> > + clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s");
> > + ep93xx_clk_data->hws[EP93XX_CLK_I2S_LRCLK] = hw;
> > +
> > + /* IrDa clk uses same pattern but no init code presents in
> > original clock driver */
> > + return 0;
> > +}
> > +
> > +static const struct of_device_id ep93xx_clk_dt_ids[] = {
> > + { .compatible = "cirrus,ep9301-syscon", },
> > + { /* sentinel */ },
> > +};
> > +
> > +static struct platform_driver ep93xx_clk_driver = {
> > + .probe = ep93xx_clk_probe,
> > + .driver = {
> > + .name = "ep93xx-clk",
> > + .of_match_table = ep93xx_clk_dt_ids,
> > + .suppress_bind_attrs = true,
> > + },
> > +};
> > +builtin_platform_driver(ep93xx_clk_driver);
> > +
> > +static void __init ep93xx_clock_init(struct device_node *np)
> > +{
> > + void __iomem *base;
> > + int i;
> > + int ret;
> > + u32 value;
> > + struct clk_hw *hw;
> > + unsigned long clk_pll1_rate;
> > + unsigned long clk_f_rate;
> > + unsigned long clk_h_rate;
> > + unsigned long clk_p_rate;
> > + unsigned long clk_pll2_rate;
> > + unsigned int clk_f_div;
> > + unsigned int clk_h_div;
> > + unsigned int clk_p_div;
> > +
> > + ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
> > + EP93XX_NUM_CLKS),
> > + GFP_KERNEL);
> > +
> > + if (!ep93xx_clk_data)
> > + return;
> > +
> > + /*
> > + * This way all clock fetched before the platform device
> > probes,
> > + * except those we assign here for early use, will be
> > deferred.
> > + */
> > + for (i = 0; i < EP93XX_NUM_CLKS; i++)
> > + ep93xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
> > +
> > + base = of_iomap(np, 0);
> > + /* Remap the system controller for the exclusive register
> > */
> > + if (IS_ERR(base)) {
> > + pr_err("failed to map base\n");
> > + return;
> > + }
> > +
> > + ep93xx_map = syscon_node_to_regmap(np);
> > + if (IS_ERR(ep93xx_map)) {
> > + pr_err("no syscon regmap\n");
> > + return;
> > + }
> > +
> > + /*
> > + * We check that the regmap works on this very first
> > access,
> > + * but as this is an MMIO-backed regmap, subsequent regmap
> > + * access is not going to fail and we skip error checks
> > from
> > + * this point.
> > + */
> > + ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
> > + if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
> > + pr_err("failed to read global status register\n");
> > + return;
> > + }
> > +
> > + hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0,
> > EP93XX_EXT_CLK_RATE);
>
> Maybe this can be registered from DT itself.
>
> > + clk_hw_register_clkdev(hw, NULL, "xtali");
> > +
> > + /* Determine the bootloader configured pll1 rate */
> > + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET1, &value);
> > + if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
> > + clk_pll1_rate = EP93XX_EXT_CLK_RATE;
> > + else
> > + clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE,
> > value);
> > +
> > + hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0,
> > clk_pll1_rate);
>
> And maybe this can be registered from wherever the regmap is created?
>
> > + clk_hw_register_clkdev(hw, NULL, "pll1");
>
> Do you need to use clkdev?
>
> > + ep93xx_clk_data->hws[EP93XX_CLK_PLL1] = hw;
> > +
> > + /* Initialize the pll1 derived clocks */
> > + clk_f_div = fclk_divisors[(value >> 25) & 0x7];
> > + clk_h_div = hclk_divisors[(value >> 20) & 0x7];
> > + clk_p_div = pclk_divisors[(value >> 18) & 0x3];
> > +
> > + hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0,
> > 1, clk_f_div);
> > + clk_f_rate = clk_get_rate(hw->clk);
> > + ep93xx_clk_data->hws[EP93XX_CLK_FCLK] = hw;
> > + hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0,
> > 1, clk_h_div);
> > + clk_h_rate = clk_get_rate(hw->clk);
> > + ep93xx_clk_data->hws[EP93XX_CLK_HCLK] = hw;
> > + hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0,
> > 1, clk_p_div);
> > + clk_p_rate = clk_get_rate(hw->clk);
> > + ep93xx_clk_data->hws[EP93XX_CLK_PCLK] = hw;
>
> Try to not use clk consumer APIs from a clk provider. In this case,
> it
> looks like some debug message, so just drop these clk_get_rate()
> calls
> and the associated printks.
>
> > +
> > + clk_hw_register_clkdev(hw, "apb_pclk", NULL);
> > +
> > + ep93xx_dma_clock_init(base);
>
> Does some interrupt or timer driver use dma? Why are these registered
> early?
>
> > +
> > + /* Determine the bootloader configured pll2 rate */
> > + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> > + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
> > + clk_pll2_rate = EP93XX_EXT_CLK_RATE;
> > + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
> > + clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE,
> > value);
> > + else
> > + clk_pll2_rate = 0;
> > +
> > + hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0,
> > clk_pll2_rate);
>
> Instead of registering a fixed rate clk here you can implemented
> recalc_rate and look at the regmap value.
>
> > + ep93xx_clk_data->hws[EP93XX_CLK_PLL2] = hw;
> > + clk_hw_register_clkdev(hw, NULL, "pll2");
> > +
> > + ep93xx_clk_data->num = EP93XX_NUM_CLKS;
> > + of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
> > ep93xx_clk_data);
> > +
> > + pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
> > + clk_pll1_rate / 1000000, clk_pll2_rate / 1000000);
> > + pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
> > + clk_f_rate / 1000000, clk_h_rate / 1000000,
> > + clk_p_rate / 1000000);
> > +}
> > +CLK_OF_DECLARE_DRIVER(ep93xx_cc, "cirrus,ep9301-syscon",
> > ep93xx_clock_init);
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
` (3 preceding siblings ...)
2023-04-26 20:56 ` [PATCH 00/43] ep93xx device tree conversion Linus Walleij
@ 2023-05-16 3:47 ` Florian Fainelli
2023-05-16 10:37 ` Nikita Shubin
2023-06-01 5:33 ` [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx Nikita Shubin
` (2 subsequent siblings)
7 siblings, 1 reply; 26+ messages in thread
From: Florian Fainelli @ 2023-05-16 3:47 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S. Miller, Jonathan Neuschäfer, Russell King (Oracle),
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Arnd Bergmann,
Bartosz Golaszewski, Brian Norris, Chuanhong Guo, Conor Dooley,
Damien Le Moal, Daniel Lezcano, Dmitry Torokhov,
Emil Renner Berthing, Eric Dumazet, Guenter Roeck,
Hartley Sweeten, Heiko Stuebner, Hitomi Hasegawa, Jakub Kicinski,
Jaroslav Kysela, Jean Delvare, Joel Stanley, Jonathan Cameron,
Krzysztof Kozlowski, Le Moal, Liam Girdwood, Liang Yang,
Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, linux-gpio, linux-ide, linux-input,
linux-kernel, linux-mtd, linux-pm, linux-pwm, linux-rtc,
linux-spi, linux-watchdog, netdev, soc
On 4/24/2023 5:34 AM, Nikita Shubin wrote:
> This series aims to convert ep93xx from platform to full device tree support.
>
> Tested on ts7250 64 RAM/128 MiB Nand flash, edb9302.
>
> Thank you Linus and Arnd for your support, review and comments, sorry if i missed something -
> these series are quite big for me.
>
> Big thanks to Alexander Sverdlin for his testing, support, review, fixes and patches.
If anyone is interested I still have a TS-7300 board [1] that is fully
functional and could be sent out to a new home.
https://www.embeddedts.com/products/TS-7300
--
Florian
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 00/43] ep93xx device tree conversion
2023-05-16 3:47 ` Florian Fainelli
@ 2023-05-16 10:37 ` Nikita Shubin
0 siblings, 0 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-05-16 10:37 UTC (permalink / raw)
To: Florian Fainelli
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
David S. Miller, Jonathan Neuschäfer, Russell King (Oracle),
Uwe Kleine-König, Alessandro Zummo, Alexander Gordeev,
Alexandre Belloni, Andy Shevchenko, Arnd Bergmann,
Bartosz Golaszewski, Brian Norris, Chuanhong Guo, Conor Dooley,
Damien Le Moal, Daniel Lezcano, Dmitry Torokhov,
Emil Renner Berthing, Eric Dumazet, Guenter Roeck,
Hartley Sweeten, Heiko Stuebner, Hitomi Hasegawa, Jakub Kicinski,
Jaroslav Kysela, Jean Delvare, Joel Stanley, Jonathan Cameron,
Krzysztof Kozlowski, Le Moal, Liam Girdwood, Liang Yang,
Linus Walleij, Lukasz Majewski, Lv Ruyi, Mark Brown,
Masahiro Yamada, Michael Turquette, Miquel Raynal,
Nathan Chancellor, Nick Desaulniers, Nicolas Saenz Julienne,
Olof Johansson, Paolo Abeni, Qin Jian, Richard Weinberger,
Rob Herring, Robert Jarzmik, Russell King, Sebastian Reichel,
Sergey Shtylyov, Stephen Boyd, Sumanth Korikkar, Sven Peter,
Takashi Iwai, Thierry Reding, Thomas Gleixner, Ulf Hansson,
Vasily Gorbik, Vignesh Raghavendra, Vinod Koul, Walker Chen,
Wim Van Sebroeck, Yinbo Zhu, alsa-devel, devicetree, dmaengine,
linux-arm-kernel, linux-clk, linux-gpio, linux-ide, linux-input,
linux-kernel, linux-mtd, linux-pm, linux-pwm, linux-rtc,
linux-spi, linux-watchdog, netdev, soc
Hello Florian!
On Mon, 2023-05-15 at 20:47 -0700, Florian Fainelli wrote:
>
>
> On 4/24/2023 5:34 AM, Nikita Shubin wrote:
> > This series aims to convert ep93xx from platform to full device
> > tree support.
> >
> > Tested on ts7250 64 RAM/128 MiB Nand flash, edb9302.
> >
> > Thank you Linus and Arnd for your support, review and comments,
> > sorry if i missed something -
> > these series are quite big for me.
> >
> > Big thanks to Alexander Sverdlin for his testing, support, review,
> > fixes and patches.
>
> If anyone is interested I still have a TS-7300 board [1] that is
> fully
> functional and could be sent out to a new home.
Thank you kindly, i'll keep this in mind !
>
> https://www.embeddedts.com/products/TS-7300
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
` (4 preceding siblings ...)
2023-05-16 3:47 ` Florian Fainelli
@ 2023-06-01 5:33 ` Nikita Shubin
2023-06-01 6:37 ` Krzysztof Kozlowski
2023-06-01 5:33 ` [PATCH v1 04/43] dt-bindings: clock: " Nikita Shubin
2023-06-01 5:33 ` [PATCH v1 05/43] clk: ep93xx: add DT support for " Nikita Shubin
7 siblings, 1 reply; 26+ messages in thread
From: Nikita Shubin @ 2023-06-01 5:33 UTC (permalink / raw)
To: Alexander Sverdlin, Arnd Bergmann, Linus Walleij, Rob Herring,
Krzysztof Kozlowski, Michael Turquette, Stephen Boyd,
Nikita Shubin
Cc: Michael Peters, Kris Bahnsen, devicetree, linux-kernel, linux-clk
This adds device tree bindings for the Cirrus Logic EP93xx.
Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
---
Notes:
v0 -> v1:
- fixed compatible - now it specifies three boards
- ts7250
- bk3
- edb9302
- fixed identation in example
- dropped labels
.../devicetree/bindings/arm/ep93xx.yaml | 107 ++++++++++++++++++
.../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +++++++++
2 files changed, 160 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
diff --git a/Documentation/devicetree/bindings/arm/ep93xx.yaml b/Documentation/devicetree/bindings/arm/ep93xx.yaml
new file mode 100644
index 000000000000..bcf9754d0763
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/ep93xx.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/ep93xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic EP93xx device tree bindings
+
+description: |+
+ The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
+
+maintainers:
+ - Alexander Sverdlin <alexander.sverdlin@gmail.com>
+ - Nikita Shubin <nikita.shubin@maquefel.me>
+
+properties:
+ $nodename:
+ const: '/'
+ compatible:
+ oneOf:
+ - description: The TS-7250 is a compact, full-featured Single Board Computer (SBC)
+ based upon the Cirrus EP9302 ARM9 CPU
+ items:
+ - const: technologic,ts7250
+ - const: cirrus,ep9301
+
+ - description: The Liebherr BK3 is a derivate from ts7250 board
+ items:
+ - const: liebherr,bk3
+ - const: cirrus,ep9301
+
+ - description: EDB302 is an evaluation board by Cirrus Logic,
+ based on a Cirrus Logic EP9302 CPU
+ items:
+ - const: cirrus,edb9302
+ - const: cirrus,ep9301
+
+ soc:
+ type: object
+ patternProperties:
+ "^.*syscon@80930000$":
+ type: object
+ properties:
+ compatible:
+ items:
+ - const: cirrus,ep9301-syscon
+ - const: syscon
+ - const: simple-mfd
+ ep9301-reboot:
+ type: object
+ properties:
+ compatible:
+ const: cirrus,ep9301-reboot
+ required:
+ - compatible
+ - reg
+ - ep9301-reboot
+
+ "^.*timer@80810000$":
+ type: object
+ properties:
+ compatible:
+ const: cirrus,ep9301-timer
+
+ required:
+ - syscon@80930000
+ - timer@80810000
+
+required:
+ - compatible
+ - soc
+
+additionalProperties: true
+
+examples:
+ - |
+ / {
+ compatible = "technologic,ts7250", "cirrus,ep9301";
+ model = "TS-7250 SBC";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "simple-bus";
+
+ syscon@80930000 {
+ compatible = "cirrus,ep9301-syscon",
+ "syscon", "simple-mfd";
+ reg = <0x80930000 0x1000>;
+
+ ep9301-reboot {
+ compatible = "cirrus,ep9301-reboot";
+ };
+ };
+
+ timer@80810000 {
+ compatible = "cirrus,ep9301-timer";
+ reg = <0x80810000 0x100>;
+ interrupt-parent = <&vic1>;
+ interrupts = <19>;
+ };
+ };
+ };
+
+...
diff --git a/include/dt-bindings/clock/cirrus,ep93xx-clock.h b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
new file mode 100644
index 000000000000..6a8cf33d811b
--- /dev/null
+++ b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
+#define DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
+
+#define EP93XX_CLK_XTALI 0
+
+#define EP93XX_CLK_PLL1 1
+#define EP93XX_CLK_FCLK 2
+#define EP93XX_CLK_HCLK 3
+#define EP93XX_CLK_PCLK 4
+#define EP93XX_CLK_PLL2 5
+
+#define EP93XX_CLK_UART 6
+
+#define EP93XX_CLK_UART1 7
+#define EP93XX_CLK_UART2 8
+#define EP93XX_CLK_UART3 9
+
+#define EP93XX_CLK_M2M0 10
+#define EP93XX_CLK_M2M1 11
+
+#define EP93XX_CLK_M2P0 12
+#define EP93XX_CLK_M2P1 13
+#define EP93XX_CLK_M2P2 14
+#define EP93XX_CLK_M2P3 15
+#define EP93XX_CLK_M2P4 16
+#define EP93XX_CLK_M2P5 17
+#define EP93XX_CLK_M2P6 18
+#define EP93XX_CLK_M2P7 19
+#define EP93XX_CLK_M2P8 20
+#define EP93XX_CLK_M2P9 21
+
+#define EP93XX_CLK_SPI 22
+
+#define EP93XX_CLK_USB 23
+
+#define EP93XX_CLK_ADC 24
+#define EP93XX_CLK_ADC_EN 25
+
+#define EP93XX_CLK_KEYPAD 26
+
+#define EP93XX_CLK_PWM 27
+
+#define EP93XX_CLK_VIDEO 28
+
+#define EP93XX_CLK_I2S_MCLK 29
+#define EP93XX_CLK_I2S_SCLK 30
+#define EP93XX_CLK_I2S_LRCLK 31
+
+
+#define EP93XX_NUM_CLKS (EP93XX_CLK_I2S_LRCLK + 1)
+
+#endif /* DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H */
--
2.37.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 04/43] dt-bindings: clock: Add Cirrus EP93xx
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
` (5 preceding siblings ...)
2023-06-01 5:33 ` [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx Nikita Shubin
@ 2023-06-01 5:33 ` Nikita Shubin
2023-06-01 6:39 ` Krzysztof Kozlowski
2023-06-01 6:40 ` Krzysztof Kozlowski
2023-06-01 5:33 ` [PATCH v1 05/43] clk: ep93xx: add DT support for " Nikita Shubin
7 siblings, 2 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-06-01 5:33 UTC (permalink / raw)
To: Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Nikita Shubin
Cc: Michael Peters, Kris Bahnsen, linux-clk, devicetree, linux-kernel
This adds device tree bindings for the Cirrus Logic EP93xx
clock block used in these SoCs.
Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
---
Notes:
v0 -> v1:
- it's now a clock controller
.../bindings/clock/cirrus,ep9301.yaml | 64 +++++++++++++++++++
1 file changed, 64 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
diff --git a/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
new file mode 100644
index 000000000000..4f9e0d483698
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/cirrus,ep9301.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic ep93xx SoC's clock controller
+
+maintainers:
+ - Nikita Shubin <nikita.shubin@maquefel.me>
+ - Alexander Sverdlin <alexander.sverdlin@gmail.com>
+
+description: |
+ Cirrus Logic EP93XX SoC clocks driver bindings. The clock
+ controller node must be defined as a child node of the ep93xx
+ system controller node.
+
+ See also:
+ - dt-bindings/clock/cirrus,ep93xx-clock.h
+
+properties:
+ compatible:
+ oneOf:
+ - const: cirrus,ep9301-clk
+ - items:
+ - enum:
+ - cirrus,ep9302-clk
+ - cirrus,ep9307-clk
+ - cirrus,ep9312-clk
+ - cirrus,ep9315-clk
+ - const: cirrus,ep9301-clk
+
+ "#clock-cells":
+ const: 1
+
+ clocks:
+ description: List of clock specifiers which are external input
+ clocks to the given clock controller.
+ items:
+ - description: reference clock
+
+required:
+ - compatible
+ - "#clock-cells"
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ clocks {
+ xtali: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <14745600>;
+ };
+ };
+
+ clock-controller {
+ #clock-cells = <1>;
+ compatible = "cirrus,ep9301-clk";
+ clocks = <&xtali>;
+ };
+...
--
2.37.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 05/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
` (6 preceding siblings ...)
2023-06-01 5:33 ` [PATCH v1 04/43] dt-bindings: clock: " Nikita Shubin
@ 2023-06-01 5:33 ` Nikita Shubin
2023-06-03 18:58 ` andy.shevchenko
7 siblings, 1 reply; 26+ messages in thread
From: Nikita Shubin @ 2023-06-01 5:33 UTC (permalink / raw)
To: Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd
Cc: Nikita Shubin, Michael Peters, Kris Bahnsen, linux-kernel, linux-clk
This is a rewrite of EP93xx timer driver in
arch/arm/mach-ep93xx/clock.c trying to do everything
the device tree way:
- convert to syscon driver
- provide clock acces via of
Co-developed-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
---
Notes:
v0 -> v1:
Stephen Boyd:
- dropped clkdev
- Kconfig sorted
- make lock name uniq
- make divisors const
- u64 rate and drop cast for calc_pll_rate
- use parent_data
- locking all the time
- reworked parents in muxes
- using clk_hw_register everywhere
- inlined defines
rfc -> v0:
Linus Walleij:
- renamed all __underscore
Alexander Sverdlin:
- "Logick" -> "Logic"
Changes by Alexander Sverdlin:
- remove pr_info
- DIV_ROUND_UP_ULL -> DIV_ROUND_CLOSEST
- fix zeroing bitfield in ep93xx_div_set_rate
- add sanity check for EP93XX_SYSCON_CHIPID_ID
- use bit index for DMA clock's
- ep93xx_clk_register_gate() takes bit index, not mask
- remove redundant define
- use DIV_ROUND_CLOSEST() everywhere to achieve frequencies closer to those
requested
- Add the forgotten configuration from the deleted
arch/arm/mach-ep93xx/core.c
drivers/clk/Kconfig | 8 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-ep93xx.c | 850 +++++++++++++++++++++++++++++++++++++++
3 files changed, 859 insertions(+)
create mode 100644 drivers/clk/clk-ep93xx.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1eef05bb1f99..acd28167b46c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -218,6 +218,14 @@ config COMMON_CLK_EN7523
This driver provides the fixed clocks and gates present on Airoha
ARM silicon.
+config COMMON_CLK_EP93XX
+ bool "Clock driver for Cirrus Logic ep93xx SoC"
+ depends on ARCH_EP93XX || COMPILE_TEST
+ select MFD_SYSCON
+ select REGMAP
+ help
+ This driver supports the SoC clocks on the Cirrus Logic ep93xx.
+
config COMMON_CLK_FSL_FLEXSPI
tristate "Clock driver for FlexSPI on Layerscape SoCs"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e3ca0d058a25..deec25ffd004 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
+obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c
new file mode 100644
index 000000000000..e83571f83b5a
--- /dev/null
+++ b/drivers/clk/clk-ep93xx.c
@@ -0,0 +1,850 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Clock control for Cirrus EP93xx chips.
+ * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
+ *
+ * Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ */
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/cirrus/ep93xx.h>
+#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
+
+#include <asm/div64.h>
+
+#define EP93XX_EXT_CLK_RATE 14745600
+#define EP93XX_EXT_RTC_RATE 32768
+
+#define EP93XX_SYSCON_POWER_STATE 0x00
+#define EP93XX_SYSCON_PWRCNT 0x04
+#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
+#define EP93XX_SYSCON_PWRCNT_USH_EN 28
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
+#define EP93XX_SYSCON_CLKSET1 0x20
+#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
+#define EP93XX_SYSCON_CLKSET2 0x24
+#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
+#define EP93XX_SYSCON_DEVCFG 0x80
+#define EP93XX_SYSCON_DEVCFG_U3EN 24
+#define EP93XX_SYSCON_DEVCFG_U2EN 20
+#define EP93XX_SYSCON_DEVCFG_U1EN 18
+#define EP93XX_SYSCON_VIDCLKDIV 0x84
+#define EP93XX_SYSCON_CLKDIV_ENABLE 15
+#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
+#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
+#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
+#define EP93XX_SYSCON_I2SCLKDIV 0x8c
+#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
+#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
+#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
+#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
+#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
+#define EP93XX_SYSCON_CHIPID 0x94
+#define EP93XX_SYSCON_CHIPID_ID 0x9213
+
+static DEFINE_SPINLOCK(ep93xx_clk_lock);
+static struct regmap *ep93xx_map;
+#define ep93xx_regmap_read(reg, val) regmap_read(ep93xx_map, reg, val)
+#define ep93xx_regmap_write(reg, val) regmap_write(ep93xx_map, reg, val)
+
+/* Keeps track of all clocks */
+static struct clk_hw_onecell_data *ep93xx_clk_data;
+
+static const char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
+static const char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
+static const char pclk_divisors[] = { 1, 2, 4, 8 };
+
+static const char adc_divisors[] = { 16, 4 };
+static const char sclk_divisors[] = { 2, 4 };
+static const char lrclk_divisors[] = { 32, 64, 128 };
+
+#define EP_PARENT(NAME) { .name = NAME, .fw_name = NAME }
+
+static const struct clk_parent_data ep93xx_clk_parents[] = {
+ EP_PARENT("xtali"),
+ EP_PARENT("pll1"),
+ EP_PARENT("pll2")
+};
+
+/*
+ * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
+ */
+static unsigned long calc_pll_rate(u64 rate, u32 config_word)
+{
+ int i;
+
+ rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
+ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
+ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
+ for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
+ rate >>= 1;
+
+ return rate;
+}
+
+struct clk_psc {
+ struct clk_hw hw;
+ unsigned int reg;
+ u8 bit_idx;
+ u32 mask;
+ u8 shift;
+ u8 width;
+ const char *div;
+ u8 num_div;
+ spinlock_t *lock;
+ bool nolock;
+};
+
+#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
+
+static int ep93xx_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+
+ return (val & BIT(psc->bit_idx)) ? 1 : 0;
+}
+
+static int ep93xx_clk_enable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val |= BIT(psc->bit_idx);
+
+ if (psc->nolock)
+ ep93xx_regmap_write(psc->reg, val);
+ else
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ spin_unlock_irqrestore(psc->lock, flags);
+
+ return 0;
+}
+
+static void ep93xx_clk_disable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~BIT(psc->bit_idx);
+
+ if (psc->nolock)
+ ep93xx_regmap_write(psc->reg, val);
+ else
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ spin_unlock_irqrestore(psc->lock, flags);
+}
+
+static const struct clk_ops clk_ep93xx_gate_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+};
+
+static struct clk_hw *ep93xx_clk_register_gate(const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ unsigned int reg,
+ u8 bit_idx,
+ bool nolock)
+{
+ struct clk_parent_data parent_data = { };
+ struct clk_init_data init = { };
+ struct clk_psc *psc;
+ int ret;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_ep93xx_gate_ops;
+ init.flags = flags;
+
+ parent_data.fw_name = parent_name;
+ parent_data.name = parent_name;
+ init.parent_data = &parent_data;
+ init.num_parents = 1;
+
+ psc->reg = reg;
+ psc->bit_idx = bit_idx;
+ psc->hw.init = &init;
+ psc->lock = &ep93xx_clk_lock;
+ psc->nolock = nolock;
+
+ ret = clk_hw_register(NULL, &psc->hw);
+ if (ret) {
+ kfree(psc);
+ return ERR_PTR(ret);
+ }
+
+ return &psc->hw;
+}
+
+static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
+ return 0;
+
+ if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
+ return 1;
+
+ return 2;
+}
+
+static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (index >= ARRAY_SIZE(ep93xx_clk_parents))
+ return -EINVAL;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
+
+ if (index != 0) {
+ val |= EP93XX_SYSCON_CLKDIV_ESEL;
+ val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
+ }
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+
+ return 0;
+}
+
+static bool is_best(unsigned long rate, unsigned long now,
+ unsigned long best)
+{
+ return abs(rate - now) < abs(rate - best);
+}
+
+static int ep93xx_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long rate = req->rate;
+ struct clk_hw *parent_best = NULL;
+ unsigned long parent_rate;
+ unsigned long best_rate = 0, actual_rate, mclk_rate;
+ unsigned long parent_rate_best;
+ int div, pdiv;
+ int i;
+
+ /*
+ * Try the two pll's and the external clock
+ * Because the valid predividers are 2, 2.5 and 3, we multiply
+ * all the clocks by 2 to avoid floating point math.
+ *
+ * This is based on the algorithm in the ep93xx raster guide:
+ * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
+ *
+ */
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
+
+ parent_rate = clk_hw_get_rate(parent);
+ mclk_rate = parent_rate * 2;
+
+ /* Try each predivider value */
+ for (pdiv = 4; pdiv <= 6; pdiv++) {
+ div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
+ if (div < 1 || div > 127)
+ continue;
+
+ actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
+
+ if (is_best(rate, actual_rate, best_rate)) {
+ best_rate = actual_rate;
+ parent_rate_best = parent_rate;
+ parent_best = parent;
+ }
+ }
+ }
+
+ if (!parent_best)
+ return -EINVAL;
+
+ req->best_parent_rate = parent_rate_best;
+ req->best_parent_hw = parent_best;
+ req->rate = best_rate;
+
+ return 0;
+}
+
+static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long rate = 0;
+ u32 val;
+ int pdiv, div;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
+ div = val & 0x7f;
+ if (div > 0)
+ rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
+
+ return rate;
+}
+
+static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ int pdiv, div, npdiv, ndiv;
+ unsigned long actual_rate, mclk_rate, rate_err = -1;
+ int found = 0;
+ u32 val;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ mclk_rate = parent_rate * 2;
+
+ for (pdiv = 4; pdiv <= 6; pdiv++) {
+ div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
+ if (div < 1 || div > 127)
+ continue;
+
+ actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
+
+ if (!found || abs(actual_rate - rate) < rate_err) {
+ npdiv = pdiv - 3;
+ ndiv = div;
+ rate_err = abs(actual_rate - rate);
+ found = 1;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ /* Clear old dividers */
+ val &= ~0x37f;
+
+ /* Set the new pdiv and div bits for the new clock rate */
+ val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ return 0;
+}
+
+static const struct clk_ops clk_ddiv_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+ .get_parent = ep93xx_mux_get_parent,
+ .set_parent = ep93xx_mux_set_parent_lock,
+ .determine_rate = ep93xx_mux_determine_rate,
+ .recalc_rate = ep93xx_ddiv_recalc_rate,
+ .set_rate = ep93xx_ddiv_set_rate,
+};
+
+static struct clk_hw *clk_hw_register_ddiv(const char *name,
+ unsigned int reg,
+ u8 bit_idx)
+{
+ struct clk_init_data init = { };
+ struct clk_psc *psc;
+ int ret;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_ddiv_ops;
+ init.flags = 0;
+ init.parent_data = ep93xx_clk_parents;
+ init.num_parents = ARRAY_SIZE(ep93xx_clk_parents);
+
+ psc->reg = reg;
+ psc->bit_idx = bit_idx;
+ psc->lock = &ep93xx_clk_lock;
+ psc->hw.init = &init;
+
+ ret = clk_hw_register(NULL, &psc->hw);
+ if (ret) {
+ kfree(psc);
+ return ERR_PTR(ret);
+ }
+
+ return &psc->hw;
+}
+
+static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+ u8 index;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ index = (val & psc->mask) >> psc->shift;
+ if (index > psc->num_div)
+ return 0;
+
+ return DIV_ROUND_CLOSEST(parent_rate, psc->div[index]);
+}
+
+static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ unsigned long best = 0, now;
+ bool assigned = false;
+ int i;
+
+ for (i = 0; i < psc->num_div; i++) {
+ if ((rate * psc->div[i]) == *parent_rate)
+ return rate;
+
+ now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
+
+ if (!assigned || is_best(rate, now, best))
+ best = now;
+ assigned = true;
+ }
+
+ return best;
+}
+
+static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ u32 val;
+ int i;
+
+ ep93xx_regmap_read(psc->reg, &val);
+ val &= ~psc->mask;
+ for (i = 0; i < psc->num_div; i++)
+ if (rate == DIV_ROUND_CLOSEST(parent_rate, psc->div[i])) {
+ val |= i << psc->shift;
+ break;
+ }
+
+ if (i == psc->num_div)
+ return -EINVAL;
+
+ ep93xx_syscon_swlocked_write(val, psc->reg);
+
+ return 0;
+}
+
+static const struct clk_ops ep93xx_div_ops = {
+ .enable = ep93xx_clk_enable,
+ .disable = ep93xx_clk_disable,
+ .is_enabled = ep93xx_clk_is_enabled,
+ .recalc_rate = ep93xx_div_recalc_rate,
+ .round_rate = ep93xx_div_round_rate,
+ .set_rate = ep93xx_div_set_rate,
+};
+
+static struct clk_hw *clk_hw_register_div(const char *name,
+ const char *parent_name,
+ unsigned int reg,
+ u8 enable_bit,
+ u8 shift,
+ u8 width,
+ const char *clk_divisors,
+ u8 num_div)
+{
+ struct clk_parent_data parent_data = { };
+ struct clk_init_data init = { };
+ struct clk_psc *psc;
+ int ret;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &ep93xx_div_ops;
+ init.flags = 0;
+ parent_data.fw_name = parent_name;
+ parent_data.name = parent_name;
+ init.parent_data = &parent_data;
+ init.num_parents = 1;
+
+ psc->reg = reg;
+ psc->bit_idx = enable_bit;
+ psc->mask = GENMASK(shift + width - 1, shift);
+ psc->shift = shift;
+ psc->div = clk_divisors;
+ psc->num_div = num_div;
+ psc->lock = &ep93xx_clk_lock;
+ psc->hw.init = &init;
+
+ ret = clk_hw_register(NULL, &psc->hw);
+ if (ret) {
+ kfree(psc);
+ return ERR_PTR(ret);
+ }
+
+ return &psc->hw;
+}
+
+struct ep93xx_gate {
+ unsigned int idx;
+ unsigned int bit;
+ const char *name;
+};
+
+static const struct ep93xx_gate ep93xx_uarts[] = {
+ { EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "uart1" },
+ { EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "uart2" },
+ { EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "uart3" },
+};
+
+static void ep93xx_uart_clock_init(void)
+{
+ unsigned int i;
+ struct clk_hw *hw;
+ u32 val;
+ unsigned int clk_uart_div;
+
+ ep93xx_regmap_read(EP93XX_SYSCON_PWRCNT, &val);
+ if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
+ clk_uart_div = 1;
+ else
+ clk_uart_div = 2;
+
+ hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_UART] = hw;
+
+ /* parenting uart gate clocks to uart clock */
+ for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
+ hw = ep93xx_clk_register_gate(ep93xx_uarts[i].name,
+ "uart",
+ CLK_SET_RATE_PARENT,
+ EP93XX_SYSCON_DEVCFG,
+ ep93xx_uarts[i].bit,
+ false);
+
+ ep93xx_clk_data->hws[ep93xx_uarts[i].idx] = hw;
+ }
+}
+
+static const struct ep93xx_gate ep93xx_dmas[] = {
+ { EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, "m2p0" },
+ { EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, "m2p1" },
+ { EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, "m2p2" },
+ { EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, "m2p3" },
+ { EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, "m2p4" },
+ { EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, "m2p5" },
+ { EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, "m2p6" },
+ { EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, "m2p7" },
+ { EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, "m2p8" },
+ { EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, "m2p9" },
+ { EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, "m2m0" },
+ { EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, "m2m1" },
+};
+
+static void ep93xx_dma_clock_init(void)
+{
+ int i;
+ struct clk_hw *hw;
+
+ for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
+ hw = ep93xx_clk_register_gate(ep93xx_dmas[i].name,
+ "hclk", 0,
+ EP93XX_SYSCON_PWRCNT,
+ ep93xx_dmas[i].bit,
+ true);
+
+ ep93xx_clk_data->hws[ep93xx_dmas[i].idx] = hw;
+ }
+}
+
+static int ep93xx_clk_probe(struct platform_device *pdev)
+{
+ unsigned int clk_usb_div;
+ unsigned long clk_spi_div;
+ struct clk_hw *hw;
+ u32 value;
+
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
+ clk_usb_div = (((value >> 28) & 0xf) + 1);
+ hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
+ hw = ep93xx_clk_register_gate("ohci-platform",
+ "usb_clk", 0,
+ EP93XX_SYSCON_PWRCNT,
+ EP93XX_SYSCON_PWRCNT_USH_EN,
+ true);
+ ep93xx_clk_data->hws[EP93XX_CLK_USB] = hw;
+
+ /*
+ * EP93xx SSP clock rate was doubled in version E2. For more information
+ * see:
+ * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+ clk_spi_div = 1;
+ if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+ clk_spi_div = 2;
+ hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_SPI] = hw;
+
+ /* pwm clock */
+ hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1);
+ ep93xx_clk_data->hws[EP93XX_CLK_PWM] = hw;
+
+ ep93xx_uart_clock_init();
+
+ /* touchscreen/adc clock */
+ hw = clk_hw_register_div("ep93xx-adc",
+ "xtali",
+ EP93XX_SYSCON_KEYTCHCLKDIV,
+ EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
+ EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
+ 1,
+ adc_divisors,
+ ARRAY_SIZE(adc_divisors));
+
+ ep93xx_clk_data->hws[EP93XX_CLK_ADC] = hw;
+
+ /* keypad clock */
+ hw = clk_hw_register_div("ep93xx-keypad",
+ "xtali",
+ EP93XX_SYSCON_KEYTCHCLKDIV,
+ EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
+ EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
+ 1,
+ adc_divisors,
+ ARRAY_SIZE(adc_divisors));
+
+ ep93xx_clk_data->hws[EP93XX_CLK_KEYPAD] = hw;
+
+ /*
+ * On reset PDIV and VDIV is set to zero, while PDIV zero
+ * means clock disable, VDIV shouldn't be zero.
+ * So i set both dividers to minimum.
+ */
+ /* ENA - Enable CLK divider. */
+ /* PDIV - 00 - Disable clock */
+ /* VDIV - at least 2 */
+ /* Check and enable video clk registers */
+ ep93xx_regmap_read(EP93XX_SYSCON_VIDCLKDIV, &value);
+ value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
+ ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV);
+
+ /* check and enable i2s clk registers */
+ ep93xx_regmap_read(EP93XX_SYSCON_I2SCLKDIV, &value);
+ value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
+ /*
+ * Override the SAI_MSTR_CLK_CFG from the I2S block and use the
+ * I2SClkDiv Register settings. LRCLK transitions on the falling SCLK
+ * edge.
+ */
+ value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
+ ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV);
+
+ /* video clk */
+ hw = clk_hw_register_ddiv("ep93xx-fb",
+ EP93XX_SYSCON_VIDCLKDIV,
+ EP93XX_SYSCON_CLKDIV_ENABLE);
+
+ ep93xx_clk_data->hws[EP93XX_CLK_VIDEO] = hw;
+
+ /* i2s clk */
+ hw = clk_hw_register_ddiv("mclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_CLKDIV_ENABLE);
+
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_MCLK] = hw;
+
+ /* i2s sclk */
+ hw = clk_hw_register_div("sclk",
+ "mclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_I2SCLKDIV_SENA,
+ 16, /* EP93XX_I2SCLKDIV_SDIV_SHIFT */
+ 1, /* EP93XX_I2SCLKDIV_SDIV_WIDTH */
+ sclk_divisors,
+ ARRAY_SIZE(sclk_divisors));
+
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_SCLK] = hw;
+
+ /* i2s lrclk */
+ hw = clk_hw_register_div("lrclk",
+ "sclk",
+ EP93XX_SYSCON_I2SCLKDIV,
+ EP93XX_SYSCON_I2SCLKDIV_SENA,
+ 17, /* EP93XX_I2SCLKDIV_LRDIV32_SHIFT */
+ 2, /* EP93XX_I2SCLKDIV_LRDIV32_WIDTH */
+ lrclk_divisors,
+ ARRAY_SIZE(lrclk_divisors));
+
+ ep93xx_clk_data->hws[EP93XX_CLK_I2S_LRCLK] = hw;
+
+ /* IrDa clk uses same pattern but no init code presents in original clock driver */
+ return 0;
+}
+
+static const struct of_device_id ep93xx_clk_dt_ids[] = {
+ { .compatible = "cirrus,ep9301-clk", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver ep93xx_clk_driver = {
+ .probe = ep93xx_clk_probe,
+ .driver = {
+ .name = "ep93xx-clk",
+ .of_match_table = ep93xx_clk_dt_ids,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(ep93xx_clk_driver);
+
+static void __init ep93xx_clock_init(struct device_node *np)
+{
+ int i;
+ int ret;
+ u32 value;
+ struct clk_hw *hw;
+ struct device_node *parent;
+ unsigned long clk_pll1_rate;
+ unsigned long clk_pll2_rate;
+ unsigned int clk_f_div;
+ unsigned int clk_h_div;
+ unsigned int clk_p_div;
+
+ ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
+ EP93XX_NUM_CLKS),
+ GFP_KERNEL);
+
+ if (!ep93xx_clk_data)
+ return;
+
+ /*
+ * This way all clock fetched before the platform device probes,
+ * except those we assign here for early use, will be deferred.
+ */
+ for (i = 0; i < EP93XX_NUM_CLKS; i++)
+ ep93xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+ parent = of_get_parent(np);
+ if (!parent) {
+ pr_err("no syscon parent for clk node\n");
+ return;
+ }
+
+ ep93xx_map = syscon_node_to_regmap(parent);
+ of_node_put(parent);
+ if (IS_ERR(ep93xx_map)) {
+ pr_err("no syscon regmap\n");
+ return;
+ }
+
+ /*
+ * We check that the regmap works on this very first access,
+ * but as this is an MMIO-backed regmap, subsequent regmap
+ * access is not going to fail and we skip error checks from
+ * this point.
+ */
+ ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
+ if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
+ pr_err("failed to read global status register\n");
+ return;
+ }
+
+ /* Determine the bootloader configured pll1 rate */
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET1, &value);
+ if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
+ clk_pll1_rate = EP93XX_EXT_CLK_RATE;
+ else
+ clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
+
+ hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate);
+ ep93xx_clk_data->hws[EP93XX_CLK_PLL1] = hw;
+
+ /* Initialize the pll1 derived clocks */
+ clk_f_div = fclk_divisors[(value >> 25) & 0x7];
+ clk_h_div = hclk_divisors[(value >> 20) & 0x7];
+ clk_p_div = pclk_divisors[(value >> 18) & 0x3];
+
+ hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_FCLK] = hw;
+ hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_HCLK] = hw;
+ hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div);
+ ep93xx_clk_data->hws[EP93XX_CLK_PCLK] = hw;
+
+ /* Dma probing uses subsys_initcall, so we require to init them early */
+ ep93xx_dma_clock_init();
+
+ /* Determine the bootloader configured pll2 rate */
+ ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
+ if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
+ clk_pll2_rate = EP93XX_EXT_CLK_RATE;
+ else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
+ clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
+ else
+ clk_pll2_rate = 0;
+
+ hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate);
+ ep93xx_clk_data->hws[EP93XX_CLK_PLL2] = hw;
+
+ ep93xx_clk_data->num = EP93XX_NUM_CLKS;
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ep93xx_clk_data);
+}
+
+CLK_OF_DECLARE_DRIVER(ep93xx, "cirrus,ep9301-clk", ep93xx_clock_init);
--
2.37.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx
2023-06-01 5:33 ` [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx Nikita Shubin
@ 2023-06-01 6:37 ` Krzysztof Kozlowski
2023-06-01 7:04 ` Nikita Shubin
0 siblings, 1 reply; 26+ messages in thread
From: Krzysztof Kozlowski @ 2023-06-01 6:37 UTC (permalink / raw)
To: Nikita Shubin, Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Rob Herring, Krzysztof Kozlowski, Michael Turquette,
Stephen Boyd
Cc: Michael Peters, Kris Bahnsen, devicetree, linux-kernel, linux-clk
On 01/06/2023 07:33, Nikita Shubin wrote:
> This adds device tree bindings for the Cirrus Logic EP93xx.
>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
You already sent v1. This patchset is attached to the previous thread
making it more complicated for me to process. This buries it deep in the
mailbox and might interfere with applying entire sets.
Is this the next version, so v3? You already had at least two versions
before, so this cannot be v1.
> ---
>
> Notes:
> v0 -> v1:
>
> - fixed compatible - now it specifies three boards
> - ts7250
> - bk3
> - edb9302
> - fixed identation in example
> - dropped labels
>
> .../devicetree/bindings/arm/ep93xx.yaml | 107 ++++++++++++++++++
> .../dt-bindings/clock/cirrus,ep93xx-clock.h | 53 +++++++++
> 2 files changed, 160 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/ep93xx.yaml
> create mode 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
>
> diff --git a/Documentation/devicetree/bindings/arm/ep93xx.yaml b/Documentation/devicetree/bindings/arm/ep93xx.yaml
> new file mode 100644
> index 000000000000..bcf9754d0763
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/ep93xx.yaml
> @@ -0,0 +1,107 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/ep93xx.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic EP93xx device tree bindings
No improvements.
> +
> +description: |+
no improvements. Do not need '|+' unless you need to preserve formatting.
> + The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
> +
> +maintainers:
> + - Alexander Sverdlin <alexander.sverdlin@gmail.com>
> + - Nikita Shubin <nikita.shubin@maquefel.me>
> +
> +properties:
> + $nodename:
> + const: '/'
> + compatible:
> + oneOf:
> + - description: The TS-7250 is a compact, full-featured Single Board Computer (SBC)
> + based upon the Cirrus EP9302 ARM9 CPU
> + items:
> + - const: technologic,ts7250
> + - const: cirrus,ep9301
> +
> + - description: The Liebherr BK3 is a derivate from ts7250 board
> + items:
> + - const: liebherr,bk3
> + - const: cirrus,ep9301
> +
> + - description: EDB302 is an evaluation board by Cirrus Logic,
> + based on a Cirrus Logic EP9302 CPU
> + items:
> + - const: cirrus,edb9302
> + - const: cirrus,ep9301
> +
> + soc:
> + type: object
> + patternProperties:
> + "^.*syscon@80930000$":
> + type: object
> + properties:
> + compatible:
> + items:
> + - const: cirrus,ep9301-syscon
> + - const: syscon
> + - const: simple-mfd
> + ep9301-reboot:
> + type: object
> + properties:
> + compatible:
> + const: cirrus,ep9301-reboot
> + required:
> + - compatible
> + - reg
> + - ep9301-reboot
> +
> + "^.*timer@80810000$":
> + type: object
> + properties:
> + compatible:
> + const: cirrus,ep9301-timer
> +
> + required:
> + - syscon@80930000
> + - timer@80810000
I don't understand what are you putting here. Why addresses are in
bindings (they should not be), why some nodes are documented in
top-level compatible. Drop all this.
Open existing files and look how it is done there.
> +
> +required:
> + - compatible
> + - soc> +
> +additionalProperties: true
> +
> +examples:
> + - |
> + / {
> + compatible = "technologic,ts7250", "cirrus,ep9301";
> + model = "TS-7250 SBC";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + compatible = "simple-bus";
> +
> + syscon@80930000 {
> + compatible = "cirrus,ep9301-syscon",
> + "syscon", "simple-mfd";
> + reg = <0x80930000 0x1000>;
> +
> + ep9301-reboot {
> + compatible = "cirrus,ep9301-reboot";
> + };
> + };
> +
> + timer@80810000 {
> + compatible = "cirrus,ep9301-timer";
> + reg = <0x80810000 0x100>;
> + interrupt-parent = <&vic1>;
> + interrupts = <19>;
> + };
> + };
> + };
Drop all this. There is no existing binding like that.
> +
> +...
> diff --git a/include/dt-bindings/clock/cirrus,ep93xx-clock.h b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
Not related to top level compatible.
> new file mode 100644
> index 000000000000..6a8cf33d811b
> --- /dev/null
> +++ b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
Dual license.
> +#ifndef DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
> +#define DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
> +
> +#define EP93XX_CLK_XTALI 0
> +
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v1 04/43] dt-bindings: clock: Add Cirrus EP93xx
2023-06-01 5:33 ` [PATCH v1 04/43] dt-bindings: clock: " Nikita Shubin
@ 2023-06-01 6:39 ` Krzysztof Kozlowski
2023-06-01 6:40 ` Krzysztof Kozlowski
1 sibling, 0 replies; 26+ messages in thread
From: Krzysztof Kozlowski @ 2023-06-01 6:39 UTC (permalink / raw)
To: Nikita Shubin, Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski
Cc: Michael Peters, Kris Bahnsen, linux-clk, devicetree, linux-kernel
On 01/06/2023 07:33, Nikita Shubin wrote:
> This adds device tree bindings for the Cirrus Logic EP93xx
> clock block used in these SoCs.
>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
>
> Notes:
> v0 -> v1:
>
> - it's now a clock controller
>
> .../bindings/clock/cirrus,ep9301.yaml | 64 +++++++++++++++++++
> 1 file changed, 64 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
>
> diff --git a/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
> new file mode 100644
> index 000000000000..4f9e0d483698
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
Filename matching compatible.
> @@ -0,0 +1,64 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/cirrus,ep9301.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic ep93xx SoC's clock controller
> +
> +maintainers:
> + - Nikita Shubin <nikita.shubin@maquefel.me>
> + - Alexander Sverdlin <alexander.sverdlin@gmail.com>
> +
> +description: |
> + Cirrus Logic EP93XX SoC clocks driver bindings. The clock
> + controller node must be defined as a child node of the ep93xx
> + system controller node.
> +
> + See also:
> + - dt-bindings/clock/cirrus,ep93xx-clock.h
> +
> +properties:
> + compatible:
> + oneOf:
> + - const: cirrus,ep9301-clk
> + - items:
> + - enum:
> + - cirrus,ep9302-clk
> + - cirrus,ep9307-clk
> + - cirrus,ep9312-clk
> + - cirrus,ep9315-clk
> + - const: cirrus,ep9301-clk
> +
> + "#clock-cells":
> + const: 1
> +
> + clocks:
> + description: List of clock specifiers which are external input
> + clocks to the given clock controller.
Drop description, it's obvious.
> + items:
> + - description: reference clock
> +
> +required:
> + - compatible
> + - "#clock-cells"
> + - clocks
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + clocks {
> + xtali: oscillator {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <14745600>;
> + };
> + };
Drop this part of example, it's obvious.
> +
> + clock-controller {
> + #clock-cells = <1>;
> + compatible = "cirrus,ep9301-clk";
compatible is always first property.
> + clocks = <&xtali>;
> + };
> +...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v1 04/43] dt-bindings: clock: Add Cirrus EP93xx
2023-06-01 5:33 ` [PATCH v1 04/43] dt-bindings: clock: " Nikita Shubin
2023-06-01 6:39 ` Krzysztof Kozlowski
@ 2023-06-01 6:40 ` Krzysztof Kozlowski
1 sibling, 0 replies; 26+ messages in thread
From: Krzysztof Kozlowski @ 2023-06-01 6:40 UTC (permalink / raw)
To: Nikita Shubin, Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski
Cc: Michael Peters, Kris Bahnsen, linux-clk, devicetree, linux-kernel
On 01/06/2023 07:33, Nikita Shubin wrote:
> This adds device tree bindings for the Cirrus Logic EP93xx
> clock block used in these SoCs.
>
> Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
> ---
>
> Notes:
> v0 -> v1:
>
> - it's now a clock controller
>
> .../bindings/clock/cirrus,ep9301.yaml | 64 +++++++++++++++++++
> 1 file changed, 64 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
>
> diff --git a/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
> new file mode 100644
> index 000000000000..4f9e0d483698
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/cirrus,ep9301.yaml
> @@ -0,0 +1,64 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/cirrus,ep9301.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic ep93xx SoC's clock controller
> +
> +maintainers:
> + - Nikita Shubin <nikita.shubin@maquefel.me>
> + - Alexander Sverdlin <alexander.sverdlin@gmail.com>
> +
> +description: |
> + Cirrus Logic EP93XX SoC clocks driver bindings. The clock
First sentence is not suitable for bindings. Describe the hardware or
skip it.
> + controller node must be defined as a child node of the ep93xx
> + system controller node.
> +
parent schema should define it...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx
2023-06-01 6:37 ` Krzysztof Kozlowski
@ 2023-06-01 7:04 ` Nikita Shubin
0 siblings, 0 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-06-01 7:04 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Alexander Sverdlin, Arnd Bergmann, Linus Walleij, Rob Herring,
Krzysztof Kozlowski, Michael Turquette, Stephen Boyd,
Michael Peters, Kris Bahnsen, devicetree, linux-kernel,
linux-clk
Hello Krzysztof!
On Thu, 1 Jun 2023 08:37:02 +0200
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> On 01/06/2023 07:33, Nikita Shubin wrote:
> > This adds device tree bindings for the Cirrus Logic EP93xx.
> >
> > Signed-off-by: Nikita Shubin <nikita.shubin@maquefel.me>
>
> You already sent v1. This patchset is attached to the previous thread
> making it more complicated for me to process. This buries it deep in
> the mailbox and might interfere with applying entire sets.
Sorry for that, i've already realized my mistake looking at my own
mailbox.
>
> Is this the next version, so v3? You already had at least two versions
> before, so this cannot be v1.
It's second on the mail lists, the first one was closed RFC.
The first was without any version, i.e. v0, this one is v1 (should be
v2).
I promise to be more careful next series.
All other comments acknowledged.
>
> > ---
> >
> > Notes:
> > v0 -> v1:
> >
> > - fixed compatible - now it specifies three boards
> > - ts7250
> > - bk3
> > - edb9302
> > - fixed identation in example
> > - dropped labels
> >
> > .../devicetree/bindings/arm/ep93xx.yaml | 107
> > ++++++++++++++++++ .../dt-bindings/clock/cirrus,ep93xx-clock.h |
> > 53 +++++++++ 2 files changed, 160 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/arm/ep93xx.yaml create mode
> > 100644 include/dt-bindings/clock/cirrus,ep93xx-clock.h
> >
> > diff --git a/Documentation/devicetree/bindings/arm/ep93xx.yaml
> > b/Documentation/devicetree/bindings/arm/ep93xx.yaml new file mode
> > 100644 index 000000000000..bcf9754d0763
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/ep93xx.yaml
> > @@ -0,0 +1,107 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/arm/ep93xx.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Cirrus Logic EP93xx device tree bindings
>
> No improvements.
>
> > +
> > +description: |+
>
> no improvements. Do not need '|+' unless you need to preserve
> formatting.
>
>
> > + The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
> > +
> > +maintainers:
> > + - Alexander Sverdlin <alexander.sverdlin@gmail.com>
> > + - Nikita Shubin <nikita.shubin@maquefel.me>
> > +
> > +properties:
> > + $nodename:
> > + const: '/'
> > + compatible:
> > + oneOf:
> > + - description: The TS-7250 is a compact, full-featured
> > Single Board Computer (SBC)
> > + based upon the Cirrus EP9302 ARM9 CPU
> > + items:
> > + - const: technologic,ts7250
> > + - const: cirrus,ep9301
> > +
> > + - description: The Liebherr BK3 is a derivate from ts7250
> > board
> > + items:
> > + - const: liebherr,bk3
> > + - const: cirrus,ep9301
> > +
> > + - description: EDB302 is an evaluation board by Cirrus Logic,
> > + based on a Cirrus Logic EP9302 CPU
> > + items:
> > + - const: cirrus,edb9302
> > + - const: cirrus,ep9301
> > +
> > + soc:
> > + type: object
> > + patternProperties:
> > + "^.*syscon@80930000$":
> > + type: object
> > + properties:
> > + compatible:
> > + items:
> > + - const: cirrus,ep9301-syscon
> > + - const: syscon
> > + - const: simple-mfd
> > + ep9301-reboot:
> > + type: object
> > + properties:
> > + compatible:
> > + const: cirrus,ep9301-reboot
> > + required:
> > + - compatible
> > + - reg
> > + - ep9301-reboot
> > +
> > + "^.*timer@80810000$":
> > + type: object
> > + properties:
> > + compatible:
> > + const: cirrus,ep9301-timer
> > +
> > + required:
> > + - syscon@80930000
> > + - timer@80810000
>
> I don't understand what are you putting here. Why addresses are in
> bindings (they should not be), why some nodes are documented in
> top-level compatible. Drop all this.
>
> Open existing files and look how it is done there.
>
> > +
> > +required:
> > + - compatible
> > + - soc> +
> > +additionalProperties: true
> > +
> > +examples:
> > + - |
> > + / {
> > + compatible = "technologic,ts7250", "cirrus,ep9301";
> > + model = "TS-7250 SBC";
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + soc {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > + compatible = "simple-bus";
> > +
> > + syscon@80930000 {
> > + compatible = "cirrus,ep9301-syscon",
> > + "syscon", "simple-mfd";
> > + reg = <0x80930000 0x1000>;
> > +
> > + ep9301-reboot {
> > + compatible = "cirrus,ep9301-reboot";
> > + };
> > + };
> > +
> > + timer@80810000 {
> > + compatible = "cirrus,ep9301-timer";
> > + reg = <0x80810000 0x100>;
> > + interrupt-parent = <&vic1>;
> > + interrupts = <19>;
> > + };
> > + };
> > + };
>
> Drop all this. There is no existing binding like that.
>
> > +
> > +...
> > diff --git a/include/dt-bindings/clock/cirrus,ep93xx-clock.h
> > b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
>
> Not related to top level compatible.
>
> > new file mode 100644
> > index 000000000000..6a8cf33d811b
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/cirrus,ep93xx-clock.h
> > @@ -0,0 +1,53 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
>
> Dual license.
>
> > +#ifndef DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
> > +#define DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
> > +
> > +#define EP93XX_CLK_XTALI 0
> > +
>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v1 05/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-06-01 5:33 ` [PATCH v1 05/43] clk: ep93xx: add DT support for " Nikita Shubin
@ 2023-06-03 18:58 ` andy.shevchenko
2023-06-20 12:37 ` Nikita Shubin
0 siblings, 1 reply; 26+ messages in thread
From: andy.shevchenko @ 2023-06-03 18:58 UTC (permalink / raw)
To: Nikita Shubin
Cc: Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd, Michael Peters, Kris Bahnsen,
linux-kernel, linux-clk
Thu, Jun 01, 2023 at 08:33:56AM +0300, Nikita Shubin kirjoitti:
> This is a rewrite of EP93xx timer driver in
> arch/arm/mach-ep93xx/clock.c trying to do everything
> the device tree way:
>
> - convert to syscon driver
> - provide clock acces via of
...
> +#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/soc/cirrus/ep93xx.h>
Can you keep them sorted?
Missing bits.h.
+ Blank line.
> +#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
> +
> +#include <asm/div64.h>
...
> +static const struct clk_parent_data ep93xx_clk_parents[] = {
> + EP_PARENT("xtali"),
> + EP_PARENT("pll1"),
> + EP_PARENT("pll2")
Keep trailing comma, it might help in case it will be extended.
> +};
...
> +static unsigned long calc_pll_rate(u64 rate, u32 config_word)
> +{
> + int i;
> +
> + rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
> + rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
> + do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
GENMASK() in all three?
> + for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
> + rate >>= 1;
I'm not sure I understand why loop is needed.
rate >>= 1 << ((config_word >> 16) & GENMASK(1, 0));
?
> + return rate;
> +}
...
> +struct clk_psc {
> + struct clk_hw hw;
> + unsigned int reg;
> + u8 bit_idx;
> + u32 mask;
> + u8 shift;
> + u8 width;
> + const char *div;
> + u8 num_div;
> + spinlock_t *lock;
> + bool nolock;
Is it important to mix different types like this? pahole can provide you a much
better layout that does not waste a lot of bytes.
> +};
...
> + return (val & BIT(psc->bit_idx)) ? 1 : 0;
!!(...) also would work, but up to you. Compiler optimizes this anyway.
...
> + unsigned long flags = 0;
Redundant assignment. *spin_lock*() are macros.
Same for all cases with *spin_lock*().
...
> +static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
> + return 0;
> +
> + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
> + return 1;
> +
> + return 2;
Wonder if switch-case can make this more explicit...
> +}
...
> + if (psc->lock)
> + spin_lock_irqsave(psc->lock, flags);
Does sparse complain on the lock? If so, the function would need a special
annotation.
...
> + ep93xx_regmap_read(psc->reg, &val);
> + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
> +
More naturally this blank line looks fter regmap_read.
> + if (index != 0) {
if (index)
also works.
> + val |= EP93XX_SYSCON_CLKDIV_ESEL;
> + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
> + }
...
> +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long rate = 0;
Instead you can invert the conditional, see below.
> + u32 val;
> + int pdiv, div;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
> + div = val & 0x7f;
GENMASK() in both cases?
> + if (div > 0)
if (div <= 0)
return 0;
> + rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
return DIV_ROUND_CLOSES(...);
> +
> + return rate;
> +}
...
> +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + int pdiv, div, npdiv, ndiv;
> + unsigned long actual_rate, mclk_rate, rate_err = -1;
ULONG_MAX instead of -1. -1 on 64-bits is not the same as ULONG_MAX
(yes, I know that this is not the case here, simply not the best constant).
> + int found = 0;
Besides using it as boolean, IIUC it's not needed if you compare
the rate_err to ULONG_MAX where required.
> + u32 val;
> +
> + ep93xx_regmap_read(psc->reg, &val);
> + mclk_rate = parent_rate * 2;
> +
> + for (pdiv = 4; pdiv <= 6; pdiv++) {
> + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> + if (div < 1 || div > 127)
> + continue;
> +
> + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
> +
Redundant blank line.
> + if (!found || abs(actual_rate - rate) < rate_err) {
> + npdiv = pdiv - 3;
> + ndiv = div;
> + rate_err = abs(actual_rate - rate);
> + found = 1;
> + }
> + }
> +
> + if (!found)
> + return -EINVAL;
> + /* Clear old dividers */
> + val &= ~0x37f;
GENMASK() ?
> + /* Set the new pdiv and div bits for the new clock rate */
> + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
> +
> + ep93xx_syscon_swlocked_write(val, psc->reg);
> +
> + return 0;
> +}
...
> +{
> + struct clk_psc *psc = to_clk_psc(hw);
> + unsigned long best = 0, now;
> + bool assigned = false;
You see, you are using here the boolean. But think about it, maybe it can be
refactored as well.
> + int i;
> +
> + for (i = 0; i < psc->num_div; i++) {
> + if ((rate * psc->div[i]) == *parent_rate)
> + return rate;
> +
> + now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
> +
> + if (!assigned || is_best(rate, now, best))
> + best = now;
> + assigned = true;
> + }
> +
> + return best;
> +}
...
> + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> + clk_usb_div = (((value >> 28) & 0xf) + 1);
GENMASK() ?
> + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
> + hw = ep93xx_clk_register_gate("ohci-platform",
> + "usb_clk", 0,
> + EP93XX_SYSCON_PWRCNT,
> + EP93XX_SYSCON_PWRCNT_USH_EN,
> + true);
...
> + /* pwm clock */
PWM
...
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
BIT() ?
...
> + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
Ditto.
...
> +static const struct of_device_id ep93xx_clk_dt_ids[] = {
> + { .compatible = "cirrus,ep9301-clk", },
Inner comma is not needed.
> + { /* sentinel */ }
> +};
...
> + ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
> + EP93XX_NUM_CLKS),
> + GFP_KERNEL);
> +
Redundant blank line.
> + if (!ep93xx_clk_data)
> + return;
...
> + ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
> + if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
GENMASK() ?
> + pr_err("failed to read global status register\n");
> + return;
> + }
...
> + /* Initialize the pll1 derived clocks */
> + clk_f_div = fclk_divisors[(value >> 25) & 0x7];
> + clk_h_div = hclk_divisors[(value >> 20) & 0x7];
> + clk_p_div = pclk_divisors[(value >> 18) & 0x3];
Ditto.
...
> +
Unneded blank line.
> +CLK_OF_DECLARE_DRIVER(ep93xx, "cirrus,ep9301-clk", ep93xx_clock_init);
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 12/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-05-15 13:31 ` Nikita Shubin
@ 2023-06-13 20:44 ` Stephen Boyd
0 siblings, 0 replies; 26+ messages in thread
From: Stephen Boyd @ 2023-06-13 20:44 UTC (permalink / raw)
To: Nikita Shubin
Cc: Arnd Bergmann, Linus Walleij, Alexander Sverdlin,
Michael Turquette, linux-kernel, linux-clk
Quoting Nikita Shubin (2023-05-15 06:31:41)
> Hello Stephen!
>
> Thank you for your review.
>
> Acknowledged all remarks, however, i didn't fully understood some of
> the requirements:
When the reply is taken out of context it is harder for me to recall
what we're talking about.
>
> > And maybe this can be registered from wherever the regmap is created?
>
> Are you suggesting that all clock from init, i.e. "pll1", "pll2",
> "hclk", "fclk", "pclk"
>
> Should be moved to SoC driver instead:
>
> https://lore.kernel.org/all/20230424123522.18302-3-nikita.shubin@maquefel.me/
>
> ?
Sure? That looks like a possibility.
>
> > Does some interrupt or timer driver use dma? Why are these registered
> > early?
>
> ep93xx_dma uses subsys_initcall(ep93xx_dma_module_init)
>
> https://elixir.bootlin.com/linux/v6.3.2/source/drivers/dma/ep93xx_dma.c#L1430
>
> I can move clk to using arch_initcall and move all stuff to probe, i
> think...
Sounds like the answer to my question is no. In which case moving to
arch_initcall() or probe will work. Please try.
>
> > Why is this in arm/ directory? Isn't it a clock controller?
>
> ep93xx clocks, reboot, pinctrl use syscon regmap and some special
> functions from SoC, i.e. "Syscon Software Lock Register" - so we are
> able to write to some registers only after writing some magik value
> there.
>
> So all above use regmap from SoC.
There can be an API in a header located in include/soc/ that implements
the magik value unlock sequence?
>
> Should make a separate clock controller like one i did for pinctrl ?
> Then it should look like:
>
> syscon@80930000 {
> compatible = "cirrus,ep9301-syscon",
> "syscon", "simple-mfd";
> reg = <0x80930000 0x1000>;
> #reset-cells = <1>;
>
> clocks {
> xtali: oscillator {
> compatible = "fixed-clock";
> #clock-cells = <0>;
> clock-frequency = <14745600>;
> };
> };
>
> clock-controller {
> #clock-cells = <1>;
> compatible = "cirrus,ep9301-clk";
> clocks = <&xtali>;
> };
> };
>
> Or even simply:
>
> clocks {
> xtali: oscillator {
> compatible = "fixed-clock";
> #clock-cells = <0>;
> clock-frequency = <14745600>;
> };
> };
>
> clock-controller {
> #clock-cells = <1>;
> compatible = "cirrus,ep9301-clk";
> clocks = <&xtali>;
> };
The DT binding shouldn't be making sub-nodes to match driver structure
of the kernel. Instead, there should be a node for a register range that
represents a device on the bus. That device may be multipurpose, in
which case it can probe as a platform driver and that platform driver
can create some number of auxiliary bus devices for the sub
functionality of the device. We shouldn't be prescribing Linux software
constructs onto the DT binding.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v1 05/43] clk: ep93xx: add DT support for Cirrus EP93xx
2023-06-03 18:58 ` andy.shevchenko
@ 2023-06-20 12:37 ` Nikita Shubin
0 siblings, 0 replies; 26+ messages in thread
From: Nikita Shubin @ 2023-06-20 12:37 UTC (permalink / raw)
To: andy.shevchenko
Cc: Alexander Sverdlin, Arnd Bergmann, Linus Walleij,
Michael Turquette, Stephen Boyd, Michael Peters, Kris Bahnsen,
linux-kernel, linux-clk
Hello Andy!
Thank you for your review!
On Sat, 2023-06-03 at 21:58 +0300, andy.shevchenko@gmail.com wrote:
> Thu, Jun 01, 2023 at 08:33:56AM +0300, Nikita Shubin kirjoitti:
> > This is a rewrite of EP93xx timer driver in
> > arch/arm/mach-ep93xx/clock.c trying to do everything
> > the device tree way:
> >
> > - convert to syscon driver
> > - provide clock acces via of
>
> ...
>
> > +#include <linux/kernel.h>
> > +#include <linux/clk.h>
> > +#include <linux/err.h>
> > +#include <linux/module.h>
> > +#include <linux/string.h>
> > +#include <linux/io.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/soc/cirrus/ep93xx.h>
>
> Can you keep them sorted?
> Missing bits.h.
>
> + Blank line.
>
> > +#include <dt-bindings/clock/cirrus,ep93xx-clock.h>
> > +
> > +#include <asm/div64.h>
>
> ...
>
> > +static const struct clk_parent_data ep93xx_clk_parents[] = {
> > + EP_PARENT("xtali"),
> > + EP_PARENT("pll1"),
> > + EP_PARENT("pll2")
>
> Keep trailing comma, it might help in case it will be extended.
>
> > +};
>
> ...
>
> > +static unsigned long calc_pll_rate(u64 rate, u32 config_word)
> > +{
> > + int i;
> > +
> > + rate *= ((config_word >> 11) & 0x1f) + 1; /*
> > X1FBD */
> > + rate *= ((config_word >> 5) & 0x3f) + 1; /*
> > X2FBD */
> > + do_div(rate, (config_word & 0x1f) + 1); /*
> > X2IPD */
>
> GENMASK() in all three?
>
> > + for (i = 0; i < ((config_word >> 16) & 3); i++) /*
> > PS */
> > + rate >>= 1;
>
> I'm not sure I understand why loop is needed.
>
> rate >>= 1 << ((config_word >> 16) & GENMASK(1, 0));
>
> ?
>
> > + return rate;
> > +}
>
> ...
>
> > +struct clk_psc {
> > + struct clk_hw hw;
> > + unsigned int reg;
> > + u8 bit_idx;
> > + u32 mask;
> > + u8 shift;
> > + u8 width;
> > + const char *div;
> > + u8 num_div;
> > + spinlock_t *lock;
> > + bool nolock;
>
> Is it important to mix different types like this? pahole can provide
> you a much
> better layout that does not waste a lot of bytes.
>
> > +};
>
> ...
>
> > + return (val & BIT(psc->bit_idx)) ? 1 : 0;
>
> !!(...) also would work, but up to you. Compiler optimizes this
> anyway.
>
> ...
>
> > + unsigned long flags = 0;
>
> Redundant assignment. *spin_lock*() are macros.
> Same for all cases with *spin_lock*().
>
> ...
>
> > +static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + u32 val;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
> > + return 0;
> > +
> > + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
> > + return 1;
> > +
> > + return 2;
>
> Wonder if switch-case can make this more explicit...
>
> > +}
>
> ...
>
> > + if (psc->lock)
> > + spin_lock_irqsave(psc->lock, flags);
>
> Does sparse complain on the lock? If so, the function would need a
> special
> annotation.
>
> ...
>
> > + ep93xx_regmap_read(psc->reg, &val);
> > + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL |
> > EP93XX_SYSCON_CLKDIV_PSEL);
> > +
>
> More naturally this blank line looks fter regmap_read.
>
> > + if (index != 0) {
>
> if (index)
>
> also works.
>
> > + val |= EP93XX_SYSCON_CLKDIV_ESEL;
> > + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
> > + }
>
> ...
>
> > +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
> > + unsigned long
> > parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long rate = 0;
>
> Instead you can invert the conditional, see below.
>
> > + u32 val;
> > + int pdiv, div;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
> > + div = val & 0x7f;
>
> GENMASK() in both cases?
Is it a good idea to replace 0x03 with GENMASK(1, 0) ?
>
> > + if (div > 0)
>
> if (div <= 0)
> return 0;
Or even
if (!div)
return 0;
>
> > + rate = DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv +
> > 3) * div);
>
> return DIV_ROUND_CLOSES(...);
>
> > +
> > + return rate;
> > +}
>
> ...
>
> > +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long
> > rate,
> > + unsigned long parent_rate)
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + int pdiv, div, npdiv, ndiv;
> > + unsigned long actual_rate, mclk_rate, rate_err = -1;
>
> ULONG_MAX instead of -1. -1 on 64-bits is not the same as ULONG_MAX
> (yes, I know that this is not the case here, simply not the best
> constant).
>
> > + int found = 0;
>
> Besides using it as boolean, IIUC it's not needed if you compare
> the rate_err to ULONG_MAX where required.
>
> > + u32 val;
> > +
> > + ep93xx_regmap_read(psc->reg, &val);
> > + mclk_rate = parent_rate * 2;
> > +
> > + for (pdiv = 4; pdiv <= 6; pdiv++) {
> > + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
> > + if (div < 1 || div > 127)
> > + continue;
> > +
> > + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv *
> > div);
>
> > +
>
> Redundant blank line.
>
> > + if (!found || abs(actual_rate - rate) < rate_err) {
> > + npdiv = pdiv - 3;
> > + ndiv = div;
> > + rate_err = abs(actual_rate - rate);
> > + found = 1;
> > + }
> > + }
> > +
> > + if (!found)
> > + return -EINVAL;
>
> > + /* Clear old dividers */
> > + val &= ~0x37f;
>
> GENMASK() ?
>
> > + /* Set the new pdiv and div bits for the new clock rate */
> > + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
> > +
> > + ep93xx_syscon_swlocked_write(val, psc->reg);
> > +
> > + return 0;
> > +}
>
> ...
>
> > +{
> > + struct clk_psc *psc = to_clk_psc(hw);
> > + unsigned long best = 0, now;
> > + bool assigned = false;
>
> You see, you are using here the boolean. But think about it, maybe it
> can be
> refactored as well.
>
> > + int i;
> > +
> > + for (i = 0; i < psc->num_div; i++) {
> > + if ((rate * psc->div[i]) == *parent_rate)
> > + return rate;
> > +
> > + now = DIV_ROUND_CLOSEST(*parent_rate, psc->div[i]);
> > +
> > + if (!assigned || is_best(rate, now, best))
> > + best = now;
> > + assigned = true;
> > + }
> > +
> > + return best;
> > +}
>
> ...
>
> > + ep93xx_regmap_read(EP93XX_SYSCON_CLKSET2, &value);
> > + clk_usb_div = (((value >> 28) & 0xf) + 1);
>
> GENMASK() ?
>
> > + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2",
> > 0, 1, clk_usb_div);
> > + hw = ep93xx_clk_register_gate("ohci-platform",
> > + "usb_clk", 0,
> > + EP93XX_SYSCON_PWRCNT,
> > + EP93XX_SYSCON_PWRCNT_USH_EN,
> > + true);
>
> ...
>
> > + /* pwm clock */
>
> PWM
>
> ...
>
> > + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
>
> BIT() ?
>
> ...
>
> > + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
>
> Ditto.
>
> ...
>
> > +static const struct of_device_id ep93xx_clk_dt_ids[] = {
> > + { .compatible = "cirrus,ep9301-clk", },
>
> Inner comma is not needed.
>
> > + { /* sentinel */ }
> > +};
>
> ...
>
> > + ep93xx_clk_data = kzalloc(struct_size(ep93xx_clk_data, hws,
> > + EP93XX_NUM_CLKS),
> > + GFP_KERNEL);
>
> > +
>
> Redundant blank line.
>
> > + if (!ep93xx_clk_data)
> > + return;
>
> ...
>
> > + ret = ep93xx_regmap_read(EP93XX_SYSCON_CHIPID, &value);
> > + if (ret || (value & 0xffff) != EP93XX_SYSCON_CHIPID_ID) {
>
> GENMASK() ?
>
> > + pr_err("failed to read global status register\n");
> > + return;
> > + }
>
> ...
>
> > + /* Initialize the pll1 derived clocks */
> > + clk_f_div = fclk_divisors[(value >> 25) & 0x7];
> > + clk_h_div = hclk_divisors[(value >> 20) & 0x7];
> > + clk_p_div = pclk_divisors[(value >> 18) & 0x3];
>
> Ditto.
>
>
> ...
>
> > +
>
> Unneded blank line.
>
> > +CLK_OF_DECLARE_DRIVER(ep93xx, "cirrus,ep9301-clk",
> > ep93xx_clock_init);
>
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2023-06-20 12:37 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-24 12:34 [PATCH 00/43] ep93xx device tree conversion Nikita Shubin
2023-04-24 11:31 ` Arnd Bergmann
[not found] ` <20230424152933.48b2ede1@kernel.org>
2023-04-25 9:20 ` Krzysztof Kozlowski
2023-04-25 13:27 ` Arnd Bergmann
2023-04-24 12:34 ` [PATCH 11/43] dt-bindings: clock: add DT bindings for Cirrus EP93xx Nikita Shubin
2023-04-24 13:28 ` Rob Herring
2023-04-28 23:15 ` Stephen Boyd
2023-04-24 12:34 ` [PATCH 12/43] clk: ep93xx: add DT support " Nikita Shubin
2023-04-24 12:01 ` Christophe JAILLET
2023-04-24 17:17 ` kernel test robot
2023-04-29 0:58 ` Stephen Boyd
2023-05-15 13:31 ` Nikita Shubin
2023-06-13 20:44 ` Stephen Boyd
2023-04-26 20:56 ` [PATCH 00/43] ep93xx device tree conversion Linus Walleij
[not found] ` <b5396ef5-3fed-4e98-8f37-a9cd4473bddc@sirena.org.uk>
2023-04-26 21:06 ` Linus Walleij
2023-05-16 3:47 ` Florian Fainelli
2023-05-16 10:37 ` Nikita Shubin
2023-06-01 5:33 ` [PATCH v1 02/43] dt-bindings: soc: Add Cirrus EP93xx Nikita Shubin
2023-06-01 6:37 ` Krzysztof Kozlowski
2023-06-01 7:04 ` Nikita Shubin
2023-06-01 5:33 ` [PATCH v1 04/43] dt-bindings: clock: " Nikita Shubin
2023-06-01 6:39 ` Krzysztof Kozlowski
2023-06-01 6:40 ` Krzysztof Kozlowski
2023-06-01 5:33 ` [PATCH v1 05/43] clk: ep93xx: add DT support for " Nikita Shubin
2023-06-03 18:58 ` andy.shevchenko
2023-06-20 12:37 ` Nikita Shubin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).