linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* 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).