The first three patches of this series modify the Ingenic CGU driver to
allow the X1000's I2S divider to be modeled as a PLL clock. This is not
really true -- it's just a fractional divider -- but doing it this way
maximizes code reuse and avoids the need for a custom clock. (Thanks to
Zhou Yanjie & Paul Cercueil for the idea.)
Patches 04-05 actually add the X1000 SoC's audio clocks. The last patch
is just a cosmetic cleanup, feel free to take it or leave it.
Aidan MacDonald (6):
clk: ingenic: Make PLL clock "od" field optional
clk: ingenic: Make PLL clock enable_bit and stable_bit optional
clk: ingenic: Add .set_rate_hook() for PLL clocks
dt-bindings: ingenic,x1000-cgu: Add audio clocks
clk: ingenic: Add X1000 audio clocks
clk: ingenic: Minor cosmetic fixups for X1000
drivers/clk/ingenic/cgu.c | 38 ++++--
drivers/clk/ingenic/cgu.h | 17 ++-
drivers/clk/ingenic/x1000-cgu.c | 119 ++++++++++++++----
include/dt-bindings/clock/ingenic,x1000-cgu.h | 4 +
4 files changed, 141 insertions(+), 37 deletions(-)
--
2.38.1
Add bindings for audio-related clocks on the Ingenic X1000 SoC.
Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Aidan MacDonald <[email protected]>
---
include/dt-bindings/clock/ingenic,x1000-cgu.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/dt-bindings/clock/ingenic,x1000-cgu.h b/include/dt-bindings/clock/ingenic,x1000-cgu.h
index f187e0719fd3..78daf44b3514 100644
--- a/include/dt-bindings/clock/ingenic,x1000-cgu.h
+++ b/include/dt-bindings/clock/ingenic,x1000-cgu.h
@@ -50,5 +50,9 @@
#define X1000_CLK_PDMA 35
#define X1000_CLK_EXCLK_DIV512 36
#define X1000_CLK_RTC 37
+#define X1000_CLK_AIC 38
+#define X1000_CLK_I2SPLLMUX 39
+#define X1000_CLK_I2SPLL 40
+#define X1000_CLK_I2S 41
#endif /* __DT_BINDINGS_CLOCK_X1000_CGU_H__ */
--
2.38.1
The set rate hook is called immediately after updating the clock
register but before the spinlock is released. This allows another
register to be updated alongside the main one, which is needed to
handle the I2S divider on some SoCs.
Signed-off-by: Aidan MacDonald <[email protected]>
---
drivers/clk/ingenic/cgu.c | 3 +++
drivers/clk/ingenic/cgu.h | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index aea01b6b2764..b6a4d4236c16 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -232,6 +232,9 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
writel(ctl, cgu->base + pll_info->reg);
+ if (pll_info->set_rate_hook)
+ pll_info->set_rate_hook(pll_info, rate, parent_rate);
+
/* If the PLL is enabled, verify that it's stable */
if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
ret = ingenic_pll_check_stable(cgu, pll_info);
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index a5e44ca7f969..99da9bd86e63 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -46,6 +46,8 @@
* -1 if there is no enable bit (ie, the PLL is always on)
* @stable_bit: the index of the stable bit in the PLL control register, or
* -1 if there is no stable bit
+ * @set_rate_hook: hook called immediately after updating the CGU register,
+ * before releasing the spinlock
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -61,6 +63,8 @@ struct ingenic_cgu_pll_info {
void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
unsigned long rate, unsigned long parent_rate,
unsigned int *m, unsigned int *n, unsigned int *od);
+ void (*set_rate_hook)(const struct ingenic_cgu_pll_info *pll_info,
+ unsigned long rate, unsigned long parent_rate);
};
/**
--
2.38.1
When the enable bit is undefined, the clock is assumed to be always
on and enable/disable is a no-op. When the stable bit is undefined,
the PLL stable check is a no-op.
Signed-off-by: Aidan MacDonald <[email protected]>
---
drivers/clk/ingenic/cgu.c | 14 +++++++++++++-
drivers/clk/ingenic/cgu.h | 10 ++++++----
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 3481129114b1..aea01b6b2764 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -189,6 +189,9 @@ static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu,
{
u32 ctl;
+ if (pll_info->stable_bit < 0)
+ return 0;
+
return readl_poll_timeout(cgu->base + pll_info->reg, ctl,
ctl & BIT(pll_info->stable_bit),
0, 100 * USEC_PER_MSEC);
@@ -230,7 +233,7 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
writel(ctl, cgu->base + pll_info->reg);
/* If the PLL is enabled, verify that it's stable */
- if (ctl & BIT(pll_info->enable_bit))
+ if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
ret = ingenic_pll_check_stable(cgu, pll_info);
spin_unlock_irqrestore(&cgu->lock, flags);
@@ -248,6 +251,9 @@ static int ingenic_pll_enable(struct clk_hw *hw)
int ret;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return 0;
+
spin_lock_irqsave(&cgu->lock, flags);
if (pll_info->bypass_bit >= 0) {
ctl = readl(cgu->base + pll_info->bypass_reg);
@@ -278,6 +284,9 @@ static void ingenic_pll_disable(struct clk_hw *hw)
unsigned long flags;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return;
+
spin_lock_irqsave(&cgu->lock, flags);
ctl = readl(cgu->base + pll_info->reg);
@@ -295,6 +304,9 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw)
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
u32 ctl;
+ if (pll_info->enable_bit < 0)
+ return true;
+
ctl = readl(cgu->base + pll_info->reg);
return !!(ctl & BIT(pll_info->enable_bit));
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 567142b584bb..a5e44ca7f969 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -42,8 +42,10 @@
* @bypass_reg: the offset of the bypass control register within the CGU
* @bypass_bit: the index of the bypass bit in the PLL control register, or
* -1 if there is no bypass bit
- * @enable_bit: the index of the enable bit in the PLL control register
- * @stable_bit: the index of the stable bit in the PLL control register
+ * @enable_bit: the index of the enable bit in the PLL control register, or
+ * -1 if there is no enable bit (ie, the PLL is always on)
+ * @stable_bit: the index of the stable bit in the PLL control register, or
+ * -1 if there is no stable bit
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -54,8 +56,8 @@ struct ingenic_cgu_pll_info {
u8 od_shift, od_bits, od_max;
unsigned bypass_reg;
s8 bypass_bit;
- u8 enable_bit;
- u8 stable_bit;
+ s8 enable_bit;
+ s8 stable_bit;
void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
unsigned long rate, unsigned long parent_rate,
unsigned int *m, unsigned int *n, unsigned int *od);
--
2.38.1
Hi Aidan,
Le mer. 26 oct. 2022 ? 20:43:42 +0100, Aidan MacDonald
<[email protected]> a ?crit :
> The set rate hook is called immediately after updating the clock
> register but before the spinlock is released. This allows another
> register to be updated alongside the main one, which is needed to
> handle the I2S divider on some SoCs.
>
> Signed-off-by: Aidan MacDonald <[email protected]>
Reviewed-by: Paul Cercueil <[email protected]>
Cheers,
-Paul
> ---
> drivers/clk/ingenic/cgu.c | 3 +++
> drivers/clk/ingenic/cgu.h | 4 ++++
> 2 files changed, 7 insertions(+)
>
> diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
> index aea01b6b2764..b6a4d4236c16 100644
> --- a/drivers/clk/ingenic/cgu.c
> +++ b/drivers/clk/ingenic/cgu.c
> @@ -232,6 +232,9 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned
> long req_rate,
>
> writel(ctl, cgu->base + pll_info->reg);
>
> + if (pll_info->set_rate_hook)
> + pll_info->set_rate_hook(pll_info, rate, parent_rate);
> +
> /* If the PLL is enabled, verify that it's stable */
> if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
> ret = ingenic_pll_check_stable(cgu, pll_info);
> diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
> index a5e44ca7f969..99da9bd86e63 100644
> --- a/drivers/clk/ingenic/cgu.h
> +++ b/drivers/clk/ingenic/cgu.h
> @@ -46,6 +46,8 @@
> * -1 if there is no enable bit (ie, the PLL is always on)
> * @stable_bit: the index of the stable bit in the PLL control
> register, or
> * -1 if there is no stable bit
> + * @set_rate_hook: hook called immediately after updating the CGU
> register,
> + * before releasing the spinlock
> */
> struct ingenic_cgu_pll_info {
> unsigned reg;
> @@ -61,6 +63,8 @@ struct ingenic_cgu_pll_info {
> void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
> unsigned long rate, unsigned long parent_rate,
> unsigned int *m, unsigned int *n, unsigned int *od);
> + void (*set_rate_hook)(const struct ingenic_cgu_pll_info *pll_info,
> + unsigned long rate, unsigned long parent_rate);
> };
>
> /**
> --
> 2.38.1
>
Hi Aidan,
Le mer. 26 oct. 2022 ? 20:43:41 +0100, Aidan MacDonald
<[email protected]> a ?crit :
> When the enable bit is undefined, the clock is assumed to be always
> on and enable/disable is a no-op. When the stable bit is undefined,
> the PLL stable check is a no-op.
>
> Signed-off-by: Aidan MacDonald <[email protected]>
Reviewed-by: Paul Cercueil <[email protected]>
Cheers,
-Paul
> ---
> drivers/clk/ingenic/cgu.c | 14 +++++++++++++-
> drivers/clk/ingenic/cgu.h | 10 ++++++----
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
> index 3481129114b1..aea01b6b2764 100644
> --- a/drivers/clk/ingenic/cgu.c
> +++ b/drivers/clk/ingenic/cgu.c
> @@ -189,6 +189,9 @@ static inline int ingenic_pll_check_stable(struct
> ingenic_cgu *cgu,
> {
> u32 ctl;
>
> + if (pll_info->stable_bit < 0)
> + return 0;
> +
> return readl_poll_timeout(cgu->base + pll_info->reg, ctl,
> ctl & BIT(pll_info->stable_bit),
> 0, 100 * USEC_PER_MSEC);
> @@ -230,7 +233,7 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned
> long req_rate,
> writel(ctl, cgu->base + pll_info->reg);
>
> /* If the PLL is enabled, verify that it's stable */
> - if (ctl & BIT(pll_info->enable_bit))
> + if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
> ret = ingenic_pll_check_stable(cgu, pll_info);
>
> spin_unlock_irqrestore(&cgu->lock, flags);
> @@ -248,6 +251,9 @@ static int ingenic_pll_enable(struct clk_hw *hw)
> int ret;
> u32 ctl;
>
> + if (pll_info->enable_bit < 0)
> + return 0;
> +
> spin_lock_irqsave(&cgu->lock, flags);
> if (pll_info->bypass_bit >= 0) {
> ctl = readl(cgu->base + pll_info->bypass_reg);
> @@ -278,6 +284,9 @@ static void ingenic_pll_disable(struct clk_hw *hw)
> unsigned long flags;
> u32 ctl;
>
> + if (pll_info->enable_bit < 0)
> + return;
> +
> spin_lock_irqsave(&cgu->lock, flags);
> ctl = readl(cgu->base + pll_info->reg);
>
> @@ -295,6 +304,9 @@ static int ingenic_pll_is_enabled(struct clk_hw
> *hw)
> const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
> u32 ctl;
>
> + if (pll_info->enable_bit < 0)
> + return true;
> +
> ctl = readl(cgu->base + pll_info->reg);
>
> return !!(ctl & BIT(pll_info->enable_bit));
> diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
> index 567142b584bb..a5e44ca7f969 100644
> --- a/drivers/clk/ingenic/cgu.h
> +++ b/drivers/clk/ingenic/cgu.h
> @@ -42,8 +42,10 @@
> * @bypass_reg: the offset of the bypass control register within the
> CGU
> * @bypass_bit: the index of the bypass bit in the PLL control
> register, or
> * -1 if there is no bypass bit
> - * @enable_bit: the index of the enable bit in the PLL control
> register
> - * @stable_bit: the index of the stable bit in the PLL control
> register
> + * @enable_bit: the index of the enable bit in the PLL control
> register, or
> + * -1 if there is no enable bit (ie, the PLL is always on)
> + * @stable_bit: the index of the stable bit in the PLL control
> register, or
> + * -1 if there is no stable bit
> */
> struct ingenic_cgu_pll_info {
> unsigned reg;
> @@ -54,8 +56,8 @@ struct ingenic_cgu_pll_info {
> u8 od_shift, od_bits, od_max;
> unsigned bypass_reg;
> s8 bypass_bit;
> - u8 enable_bit;
> - u8 stable_bit;
> + s8 enable_bit;
> + s8 stable_bit;
> void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
> unsigned long rate, unsigned long parent_rate,
> unsigned int *m, unsigned int *n, unsigned int *od);
> --
> 2.38.1
>
Quoting Aidan MacDonald (2022-10-26 12:43:42)
> The set rate hook is called immediately after updating the clock
> register but before the spinlock is released. This allows another
> register to be updated alongside the main one, which is needed to
> handle the I2S divider on some SoCs.
>
> Signed-off-by: Aidan MacDonald <[email protected]>
> ---
Applied to clk-next
Quoting Aidan MacDonald (2022-10-26 12:43:43)
> Add bindings for audio-related clocks on the Ingenic X1000 SoC.
>
> Acked-by: Krzysztof Kozlowski <[email protected]>
> Signed-off-by: Aidan MacDonald <[email protected]>
> ---
Applied to clk-next
Quoting Aidan MacDonald (2022-10-26 12:43:41)
> When the enable bit is undefined, the clock is assumed to be always
> on and enable/disable is a no-op. When the stable bit is undefined,
> the PLL stable check is a no-op.
>
> Signed-off-by: Aidan MacDonald <[email protected]>
> ---
Applied to clk-next