|  | // 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/bits.h> | 
|  | #include <linux/cleanup.h> | 
|  | #include <linux/clk-provider.h> | 
|  | #include <linux/math.h> | 
|  | #include <linux/platform_device.h> | 
|  | #include <linux/regmap.h> | 
|  | #include <linux/spinlock.h> | 
|  |  | 
|  | #include <linux/soc/cirrus/ep93xx.h> | 
|  | #include <dt-bindings/clock/cirrus,ep9301-syscon.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_MASK	GENMASK(14, 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_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 | 
|  |  | 
|  | #define EP93XX_FIXED_CLK_COUNT		21 | 
|  |  | 
|  | static const char ep93xx_adc_divisors[] = { 16, 4 }; | 
|  | static const char ep93xx_sclk_divisors[] = { 2, 4 }; | 
|  | static const char ep93xx_lrclk_divisors[] = { 32, 64, 128 }; | 
|  |  | 
|  | struct ep93xx_clk { | 
|  | struct clk_hw hw; | 
|  | u16 idx; | 
|  | u16 reg; | 
|  | u32 mask; | 
|  | u8 bit_idx; | 
|  | u8 shift; | 
|  | u8 width; | 
|  | u8 num_div; | 
|  | const char *div; | 
|  | }; | 
|  |  | 
|  | struct ep93xx_clk_priv { | 
|  | spinlock_t lock; | 
|  | struct ep93xx_regmap_adev *aux_dev; | 
|  | struct device *dev; | 
|  | void __iomem *base; | 
|  | struct regmap *map; | 
|  | struct clk_hw *fixed[EP93XX_FIXED_CLK_COUNT]; | 
|  | struct ep93xx_clk reg[]; | 
|  | }; | 
|  |  | 
|  | static struct ep93xx_clk *ep93xx_clk_from(struct clk_hw *hw) | 
|  | { | 
|  | return container_of(hw, struct ep93xx_clk, hw); | 
|  | } | 
|  |  | 
|  | static struct ep93xx_clk_priv *ep93xx_priv_from(struct ep93xx_clk *clk) | 
|  | { | 
|  | return container_of(clk, struct ep93xx_clk_priv, reg[clk->idx]); | 
|  | } | 
|  |  | 
|  | static void ep93xx_clk_write(struct ep93xx_clk_priv *priv, unsigned int reg, unsigned int val) | 
|  | { | 
|  | struct ep93xx_regmap_adev *aux = priv->aux_dev; | 
|  |  | 
|  | aux->write(aux->map, aux->lock, reg, val); | 
|  | } | 
|  |  | 
|  | static int ep93xx_clk_is_enabled(struct clk_hw *hw) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  |  | 
|  | return !!(val & BIT(clk->bit_idx)); | 
|  | } | 
|  |  | 
|  | static int ep93xx_clk_enable(struct clk_hw *hw) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  |  | 
|  | guard(spinlock_irqsave)(&priv->lock); | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | val |= BIT(clk->bit_idx); | 
|  |  | 
|  | ep93xx_clk_write(priv, clk->reg, val); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void ep93xx_clk_disable(struct clk_hw *hw) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  |  | 
|  | guard(spinlock_irqsave)(&priv->lock); | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | val &= ~BIT(clk->bit_idx); | 
|  |  | 
|  | ep93xx_clk_write(priv, clk->reg, val); | 
|  | } | 
|  |  | 
|  | static const struct clk_ops clk_ep93xx_gate_ops = { | 
|  | .enable = ep93xx_clk_enable, | 
|  | .disable = ep93xx_clk_disable, | 
|  | .is_enabled = ep93xx_clk_is_enabled, | 
|  | }; | 
|  |  | 
|  | static int ep93xx_clk_register_gate(struct ep93xx_clk *clk, | 
|  | const char *name, | 
|  | struct clk_parent_data *parent_data, | 
|  | unsigned long flags, | 
|  | unsigned int reg, | 
|  | u8 bit_idx) | 
|  | { | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | struct clk_init_data init = { }; | 
|  |  | 
|  | init.name = name; | 
|  | init.ops = &clk_ep93xx_gate_ops; | 
|  | init.flags = flags; | 
|  | init.parent_data = parent_data; | 
|  | init.num_parents = 1; | 
|  |  | 
|  | clk->reg = reg; | 
|  | clk->bit_idx = bit_idx; | 
|  | clk->hw.init = &init; | 
|  |  | 
|  | return devm_clk_hw_register(priv->dev, &clk->hw); | 
|  | } | 
|  |  | 
|  | static u8 ep93xx_mux_get_parent(struct clk_hw *hw) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  |  | 
|  | val &= EP93XX_SYSCON_CLKDIV_MASK; | 
|  |  | 
|  | switch (val) { | 
|  | case EP93XX_SYSCON_CLKDIV_ESEL: | 
|  | return 1; /* PLL1 */ | 
|  | case EP93XX_SYSCON_CLKDIV_MASK: | 
|  | return 2; /* PLL2 */ | 
|  | default: | 
|  | return 0; /* XTALI */ | 
|  | }; | 
|  | } | 
|  |  | 
|  | static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  |  | 
|  | if (index >= 3) | 
|  | return -EINVAL; | 
|  |  | 
|  | guard(spinlock_irqsave)(&priv->lock); | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | val &= ~(EP93XX_SYSCON_CLKDIV_MASK); | 
|  | val |= index > 0 ? EP93XX_SYSCON_CLKDIV_ESEL : 0; | 
|  | val |= index > 1 ? EP93XX_SYSCON_CLKDIV_PSEL : 0; | 
|  |  | 
|  | ep93xx_clk_write(priv, clk->reg, val); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static bool is_best(unsigned long rate, unsigned long now, | 
|  | unsigned long best) | 
|  | { | 
|  | return abs_diff(rate, now) < abs_diff(rate, best); | 
|  | } | 
|  |  | 
|  | static int ep93xx_mux_determine_rate(struct clk_hw *hw, | 
|  | struct clk_rate_request *req) | 
|  | { | 
|  | unsigned long best_rate = 0, actual_rate, mclk_rate; | 
|  | unsigned long rate = req->rate; | 
|  | struct clk_hw *parent_best = NULL; | 
|  | unsigned long parent_rate_best; | 
|  | unsigned long parent_rate; | 
|  | int div, pdiv; | 
|  | unsigned 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 (!in_range(div, 1, 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 ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | unsigned int pdiv, div; | 
|  | u32 val; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | pdiv = (val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & GENMASK(1, 0); | 
|  | div = val & GENMASK(6, 0); | 
|  | if (!div) | 
|  | return 0; | 
|  |  | 
|  | return DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div); | 
|  | } | 
|  |  | 
|  | static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, | 
|  | unsigned long parent_rate) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | int pdiv, div, npdiv, ndiv; | 
|  | unsigned long actual_rate, mclk_rate, rate_err = ULONG_MAX; | 
|  | u32 val; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | mclk_rate = parent_rate * 2; | 
|  |  | 
|  | for (pdiv = 4; pdiv <= 6; pdiv++) { | 
|  | div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv); | 
|  | if (!in_range(div, 1, 127)) | 
|  | continue; | 
|  |  | 
|  | actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div); | 
|  | if (abs(actual_rate - rate) < rate_err) { | 
|  | npdiv = pdiv - 3; | 
|  | ndiv = div; | 
|  | rate_err = abs(actual_rate - rate); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (rate_err == ULONG_MAX) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* | 
|  | * Clear old dividers. | 
|  | * Bit 7 is reserved bit in all ClkDiv registers. | 
|  | */ | 
|  | val &= ~(GENMASK(9, 0) & ~BIT(7)); | 
|  |  | 
|  | /* Set the new pdiv and div bits for the new clock rate */ | 
|  | val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv; | 
|  |  | 
|  | ep93xx_clk_write(priv, clk->reg, val); | 
|  |  | 
|  | 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 int ep93xx_clk_register_ddiv(struct ep93xx_clk *clk, | 
|  | const char *name, | 
|  | struct clk_parent_data *parent_data, | 
|  | u8 num_parents, | 
|  | unsigned int reg, | 
|  | u8 bit_idx) | 
|  | { | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | struct clk_init_data init = { }; | 
|  |  | 
|  | init.name = name; | 
|  | init.ops = &clk_ddiv_ops; | 
|  | init.flags = 0; | 
|  | init.parent_data = parent_data; | 
|  | init.num_parents = num_parents; | 
|  |  | 
|  | clk->reg = reg; | 
|  | clk->bit_idx = bit_idx; | 
|  | clk->hw.init = &init; | 
|  |  | 
|  | return devm_clk_hw_register(priv->dev, &clk->hw); | 
|  | } | 
|  |  | 
|  | static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, | 
|  | unsigned long parent_rate) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | u32 val; | 
|  | u8 index; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | index = (val & clk->mask) >> clk->shift; | 
|  | if (index >= clk->num_div) | 
|  | return 0; | 
|  |  | 
|  | return DIV_ROUND_CLOSEST(parent_rate, clk->div[index]); | 
|  | } | 
|  |  | 
|  | static int ep93xx_div_determine_rate(struct clk_hw *hw, | 
|  | struct clk_rate_request *req) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | unsigned long best = 0, now; | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; i < clk->num_div; i++) { | 
|  | if (req->rate * clk->div[i] == req->best_parent_rate) | 
|  | return 0; | 
|  |  | 
|  | now = DIV_ROUND_CLOSEST(req->best_parent_rate, clk->div[i]); | 
|  | if (!best || is_best(req->rate, now, best)) | 
|  | best = now; | 
|  | } | 
|  |  | 
|  | req->rate = best; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate, | 
|  | unsigned long parent_rate) | 
|  | { | 
|  | struct ep93xx_clk *clk = ep93xx_clk_from(hw); | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | unsigned int i; | 
|  | u32 val; | 
|  |  | 
|  | regmap_read(priv->map, clk->reg, &val); | 
|  | val &= ~clk->mask; | 
|  | for (i = 0; i < clk->num_div; i++) | 
|  | if (rate == DIV_ROUND_CLOSEST(parent_rate, clk->div[i])) | 
|  | break; | 
|  |  | 
|  | if (i == clk->num_div) | 
|  | return -EINVAL; | 
|  |  | 
|  | val |= i << clk->shift; | 
|  |  | 
|  | ep93xx_clk_write(priv, clk->reg, val); | 
|  |  | 
|  | 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, | 
|  | .determine_rate = ep93xx_div_determine_rate, | 
|  | .set_rate = ep93xx_div_set_rate, | 
|  | }; | 
|  |  | 
|  | static int ep93xx_register_div(struct ep93xx_clk *clk, | 
|  | const char *name, | 
|  | const struct clk_parent_data *parent_data, | 
|  | unsigned int reg, | 
|  | u8 enable_bit, | 
|  | u8 shift, | 
|  | u8 width, | 
|  | const char *clk_divisors, | 
|  | u8 num_div) | 
|  | { | 
|  | struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); | 
|  | struct clk_init_data init = { }; | 
|  |  | 
|  | init.name = name; | 
|  | init.ops = &ep93xx_div_ops; | 
|  | init.flags = 0; | 
|  | init.parent_data = parent_data; | 
|  | init.num_parents = 1; | 
|  |  | 
|  | clk->reg = reg; | 
|  | clk->bit_idx = enable_bit; | 
|  | clk->mask = GENMASK(shift + width - 1, shift); | 
|  | clk->shift = shift; | 
|  | clk->div = clk_divisors; | 
|  | clk->num_div = num_div; | 
|  | clk->hw.init = &init; | 
|  |  | 
|  | return devm_clk_hw_register(priv->dev, &clk->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 int ep93xx_uart_clock_init(struct ep93xx_clk_priv *priv) | 
|  | { | 
|  | struct clk_parent_data parent_data = { }; | 
|  | unsigned int i, idx, clk_uart_div; | 
|  | struct ep93xx_clk *clk; | 
|  | u32 val; | 
|  | int ret; | 
|  |  | 
|  | regmap_read(priv->map, EP93XX_SYSCON_PWRCNT, &val); | 
|  | if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD) | 
|  | clk_uart_div = 1; | 
|  | else | 
|  | clk_uart_div = 2; | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_UART] = | 
|  | devm_clk_hw_register_fixed_factor_index(priv->dev, "uart", | 
|  | 0, /* XTALI external clock */ | 
|  | 0, 1, clk_uart_div); | 
|  | parent_data.hw = priv->fixed[EP93XX_CLK_UART]; | 
|  |  | 
|  | /* parenting uart gate clocks to uart clock */ | 
|  | for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) { | 
|  | idx = ep93xx_uarts[i].idx - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | ret = ep93xx_clk_register_gate(clk, | 
|  | ep93xx_uarts[i].name, | 
|  | &parent_data, CLK_SET_RATE_PARENT, | 
|  | EP93XX_SYSCON_DEVCFG, | 
|  | ep93xx_uarts[i].bit); | 
|  | if (ret) | 
|  | return dev_err_probe(priv->dev, ret, | 
|  | "failed to register uart[%d] clock\n", i); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct ep93xx_gate ep93xx_dmas[] = { | 
|  | { EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, "m2m0" }, | 
|  | { EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, "m2m1" }, | 
|  | { 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" }, | 
|  | }; | 
|  |  | 
|  | static int ep93xx_dma_clock_init(struct ep93xx_clk_priv *priv) | 
|  | { | 
|  | struct clk_parent_data parent_data = { }; | 
|  | unsigned int i, idx; | 
|  |  | 
|  | parent_data.hw = priv->fixed[EP93XX_CLK_HCLK]; | 
|  | for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) { | 
|  | idx = ep93xx_dmas[i].idx; | 
|  | priv->fixed[idx] = devm_clk_hw_register_gate_parent_data(priv->dev, | 
|  | ep93xx_dmas[i].name, | 
|  | &parent_data, 0, | 
|  | priv->base + EP93XX_SYSCON_PWRCNT, | 
|  | ep93xx_dmas[i].bit, | 
|  | 0, | 
|  | &priv->lock); | 
|  | if (IS_ERR(priv->fixed[idx])) | 
|  | return PTR_ERR(priv->fixed[idx]); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct clk_hw *of_clk_ep93xx_get(struct of_phandle_args *clkspec, void *data) | 
|  | { | 
|  | struct ep93xx_clk_priv *priv = data; | 
|  | unsigned int idx = clkspec->args[0]; | 
|  |  | 
|  | if (idx < EP93XX_CLK_UART1) | 
|  | return priv->fixed[idx]; | 
|  |  | 
|  | if (idx <= EP93XX_CLK_I2S_LRCLK) | 
|  | return &priv->reg[idx - EP93XX_CLK_UART1].hw; | 
|  |  | 
|  | return ERR_PTR(-EINVAL); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS | 
|  | */ | 
|  | static unsigned long calc_pll_rate(u64 rate, u32 config_word) | 
|  | { | 
|  | rate *= ((config_word >> 11) & GENMASK(4, 0)) + 1;	/* X1FBD */ | 
|  | rate *= ((config_word >> 5) & GENMASK(5, 0)) + 1;	/* X2FBD */ | 
|  | do_div(rate, (config_word & GENMASK(4, 0)) + 1);	/* X2IPD */ | 
|  | rate >>= (config_word >> 16) & GENMASK(1, 0);		/* PS */ | 
|  |  | 
|  | return rate; | 
|  | } | 
|  |  | 
|  | static int ep93xx_plls_init(struct ep93xx_clk_priv *priv) | 
|  | { | 
|  | 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 }; | 
|  | struct clk_parent_data xtali = { .index = 0 }; | 
|  | unsigned int clk_f_div, clk_h_div, clk_p_div; | 
|  | unsigned long clk_pll1_rate, clk_pll2_rate; | 
|  | struct device *dev = priv->dev; | 
|  | struct clk_hw *hw, *pll1; | 
|  | u32 value; | 
|  |  | 
|  | /* Determine the bootloader configured pll1 rate */ | 
|  | regmap_read(priv->map, EP93XX_SYSCON_CLKSET1, &value); | 
|  |  | 
|  | if (value & EP93XX_SYSCON_CLKSET1_NBYP1) | 
|  | clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); | 
|  | else | 
|  | clk_pll1_rate = EP93XX_EXT_CLK_RATE; | 
|  |  | 
|  | pll1 = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll1", &xtali, | 
|  | 0, clk_pll1_rate); | 
|  | if (IS_ERR(pll1)) | 
|  | return PTR_ERR(pll1); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_PLL1] = pll1; | 
|  |  | 
|  | /* Initialize the pll1 derived clocks */ | 
|  | clk_f_div = fclk_divisors[(value >> 25) & GENMASK(2, 0)]; | 
|  | clk_h_div = hclk_divisors[(value >> 20) & GENMASK(2, 0)]; | 
|  | clk_p_div = pclk_divisors[(value >> 18) & GENMASK(1, 0)]; | 
|  |  | 
|  | hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "fclk", pll1, 0, 1, clk_f_div); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_FCLK] = hw; | 
|  |  | 
|  | hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "hclk", pll1, 0, 1, clk_h_div); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_HCLK] = hw; | 
|  |  | 
|  | hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "pclk", hw, 0, 1, clk_p_div); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_PCLK] = hw; | 
|  |  | 
|  | /* Determine the bootloader configured pll2 rate */ | 
|  | regmap_read(priv->map, 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 = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll2", &xtali, | 
|  | 0, clk_pll2_rate); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_PLL2] = hw; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ep93xx_clk_probe(struct auxiliary_device *adev, | 
|  | const struct auxiliary_device_id *id) | 
|  | { | 
|  | struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev); | 
|  | struct clk_parent_data xtali = { .index = 0 }; | 
|  | struct clk_parent_data ddiv_pdata[3] = { }; | 
|  | unsigned int clk_spi_div, clk_usb_div; | 
|  | struct clk_parent_data pdata = {}; | 
|  | struct device *dev = &adev->dev; | 
|  | struct ep93xx_clk_priv *priv; | 
|  | struct ep93xx_clk *clk; | 
|  | struct clk_hw *hw; | 
|  | unsigned int idx; | 
|  | int ret; | 
|  | u32 value; | 
|  |  | 
|  | priv = devm_kzalloc(dev, struct_size(priv, reg, 10), GFP_KERNEL); | 
|  | if (!priv) | 
|  | return -ENOMEM; | 
|  |  | 
|  | spin_lock_init(&priv->lock); | 
|  | priv->dev = dev; | 
|  | priv->aux_dev = rdev; | 
|  | priv->map = rdev->map; | 
|  | priv->base = rdev->base; | 
|  |  | 
|  | ret = ep93xx_plls_init(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | regmap_read(priv->map, EP93XX_SYSCON_CLKSET2, &value); | 
|  | clk_usb_div = (value >> 28 & GENMASK(3, 0)) + 1; | 
|  | hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "usb_clk", | 
|  | priv->fixed[EP93XX_CLK_PLL2], 0, 1, | 
|  | clk_usb_div); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_USB] = hw; | 
|  |  | 
|  | ret = ep93xx_uart_clock_init(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | ret = ep93xx_dma_clock_init(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | clk_spi_div = id->driver_data; | 
|  | hw = devm_clk_hw_register_fixed_factor_index(dev, "ep93xx-spi.0", | 
|  | 0, /* XTALI external clock */ | 
|  | 0, 1, clk_spi_div); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_SPI] = hw; | 
|  |  | 
|  | /* PWM clock */ | 
|  | hw = devm_clk_hw_register_fixed_factor_index(dev, "pwm_clk", 0, /* XTALI external clock */ | 
|  | 0, 1, 1); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_PWM] = hw; | 
|  |  | 
|  | /* USB clock */ | 
|  | pdata.hw = priv->fixed[EP93XX_CLK_USB]; | 
|  | hw = devm_clk_hw_register_gate_parent_data(priv->dev, "ohci-platform", &pdata, | 
|  | 0, priv->base + EP93XX_SYSCON_PWRCNT, | 
|  | EP93XX_SYSCON_PWRCNT_USH_EN, 0, | 
|  | &priv->lock); | 
|  | if (IS_ERR(hw)) | 
|  | return PTR_ERR(hw); | 
|  |  | 
|  | priv->fixed[EP93XX_CLK_USB] = hw; | 
|  |  | 
|  | ddiv_pdata[0].index = 0; /* XTALI external clock */ | 
|  | ddiv_pdata[1].hw = priv->fixed[EP93XX_CLK_PLL1]; | 
|  | ddiv_pdata[2].hw = priv->fixed[EP93XX_CLK_PLL2]; | 
|  |  | 
|  | /* touchscreen/ADC clock */ | 
|  | idx = EP93XX_CLK_ADC - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | ret = ep93xx_register_div(clk, "ep93xx-adc", &xtali, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV_TSEN, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV_ADIV, | 
|  | 1, | 
|  | ep93xx_adc_divisors, | 
|  | ARRAY_SIZE(ep93xx_adc_divisors)); | 
|  |  | 
|  |  | 
|  | /* keypad clock */ | 
|  | idx = EP93XX_CLK_KEYPAD - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | ret = ep93xx_register_div(clk, "ep93xx-keypad", &xtali, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV_KEN, | 
|  | EP93XX_SYSCON_KEYTCHCLKDIV_KDIV, | 
|  | 1, | 
|  | ep93xx_adc_divisors, | 
|  | ARRAY_SIZE(ep93xx_adc_divisors)); | 
|  |  | 
|  | /* | 
|  | * On reset PDIV and VDIV is set to zero, while PDIV zero | 
|  | * means clock disable, VDIV shouldn't be zero. | 
|  | * So we set both video and i2s dividers to minimum. | 
|  | * ENA - Enable CLK divider. | 
|  | * PDIV - 00 - Disable clock | 
|  | * VDIV - at least 2 | 
|  | */ | 
|  |  | 
|  | /* Check and enable video clk registers */ | 
|  | regmap_read(priv->map, EP93XX_SYSCON_VIDCLKDIV, &value); | 
|  | value |= BIT(EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; | 
|  | ep93xx_clk_write(priv, EP93XX_SYSCON_VIDCLKDIV, value); | 
|  |  | 
|  | /* Check and enable i2s clk registers */ | 
|  | regmap_read(priv->map, EP93XX_SYSCON_I2SCLKDIV, &value); | 
|  | value |= BIT(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_clk_write(priv, EP93XX_SYSCON_I2SCLKDIV, value); | 
|  |  | 
|  | /* video clk */ | 
|  | idx = EP93XX_CLK_VIDEO - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | ret = ep93xx_clk_register_ddiv(clk, "ep93xx-fb", | 
|  | ddiv_pdata, ARRAY_SIZE(ddiv_pdata), | 
|  | EP93XX_SYSCON_VIDCLKDIV, | 
|  | EP93XX_SYSCON_CLKDIV_ENABLE); | 
|  |  | 
|  | /* i2s clk */ | 
|  | idx = EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | ret = ep93xx_clk_register_ddiv(clk, "mclk", | 
|  | ddiv_pdata, ARRAY_SIZE(ddiv_pdata), | 
|  | EP93XX_SYSCON_I2SCLKDIV, | 
|  | EP93XX_SYSCON_CLKDIV_ENABLE); | 
|  |  | 
|  | /* i2s sclk */ | 
|  | idx = EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | pdata.hw = &priv->reg[EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1].hw; | 
|  | ret = ep93xx_register_div(clk, "sclk", &pdata, | 
|  | EP93XX_SYSCON_I2SCLKDIV, | 
|  | EP93XX_SYSCON_I2SCLKDIV_SENA, | 
|  | 16, /* EP93XX_I2SCLKDIV_SDIV_SHIFT */ | 
|  | 1,  /* EP93XX_I2SCLKDIV_SDIV_WIDTH */ | 
|  | ep93xx_sclk_divisors, | 
|  | ARRAY_SIZE(ep93xx_sclk_divisors)); | 
|  |  | 
|  | /* i2s lrclk */ | 
|  | idx = EP93XX_CLK_I2S_LRCLK - EP93XX_CLK_UART1; | 
|  | clk = &priv->reg[idx]; | 
|  | clk->idx = idx; | 
|  | pdata.hw = &priv->reg[EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1].hw; | 
|  | ret = ep93xx_register_div(clk, "lrclk", &pdata, | 
|  | EP93XX_SYSCON_I2SCLKDIV, | 
|  | EP93XX_SYSCON_I2SCLKDIV_SENA, | 
|  | 17, /* EP93XX_I2SCLKDIV_LRDIV32_SHIFT */ | 
|  | 2,  /* EP93XX_I2SCLKDIV_LRDIV32_WIDTH */ | 
|  | ep93xx_lrclk_divisors, | 
|  | ARRAY_SIZE(ep93xx_lrclk_divisors)); | 
|  |  | 
|  | /* IrDa clk uses same pattern but no init code presents in original clock driver */ | 
|  | return devm_of_clk_add_hw_provider(priv->dev, of_clk_ep93xx_get, priv); | 
|  | } | 
|  |  | 
|  | static const struct auxiliary_device_id ep93xx_clk_ids[] = { | 
|  | { .name = "soc_ep93xx.clk-ep93xx", .driver_data = 2, }, | 
|  | { .name = "soc_ep93xx.clk-ep93xx.e2", .driver_data = 1, }, | 
|  | { /* sentinel */ } | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(auxiliary, ep93xx_clk_ids); | 
|  |  | 
|  | static struct auxiliary_driver ep93xx_clk_driver = { | 
|  | .probe		= ep93xx_clk_probe, | 
|  | .id_table	= ep93xx_clk_ids, | 
|  | }; | 
|  | module_auxiliary_driver(ep93xx_clk_driver); | 
|  |  | 
|  | MODULE_LICENSE("GPL"); | 
|  | MODULE_AUTHOR("Nikita Shubin <nikita.shubin@maquefel.me>"); | 
|  | MODULE_DESCRIPTION("Clock control for Cirrus EP93xx chips"); |