Commit e4cfb823 authored by Alexandre Belloni's avatar Alexandre Belloni Committed by Stephen Boyd
Browse files

clk: at91: allow configuring generated PCR layout



The PCR register layout for GCLKCSS is changing for the future SoCs, allow
configuring it.

Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent cb4f4949
Loading
Loading
Loading
Loading
+25 −23
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 *
 */

#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
@@ -31,6 +32,7 @@ struct clk_generated {
	spinlock_t *lock;
	u32 id;
	u32 gckdiv;
	const struct clk_pcr_layout *layout;
	u8 parent_id;
	bool audio_pll_allowed;
};
@@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw)
		 __func__, gck->gckdiv, gck->parent_id);

	spin_lock_irqsave(gck->lock, flags);
	regmap_write(gck->regmap, AT91_PMC_PCR,
		     (gck->id & AT91_PMC_PCR_PID_MASK));
	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
			   AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
			   AT91_PMC_PCR_GCKCSS(gck->parent_id) |
			   AT91_PMC_PCR_CMD |
			   AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
	regmap_write(gck->regmap, gck->layout->offset,
		     (gck->id & gck->layout->pid_mask));
	regmap_update_bits(gck->regmap, gck->layout->offset,
			   AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask |
			   gck->layout->cmd | AT91_PMC_PCR_GCKEN,
			   field_prep(gck->layout->gckcss_mask, gck->parent_id) |
			   gck->layout->cmd |
			   FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) |
			   AT91_PMC_PCR_GCKEN);
	spin_unlock_irqrestore(gck->lock, flags);
	return 0;
@@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw)
	unsigned long flags;

	spin_lock_irqsave(gck->lock, flags);
	regmap_write(gck->regmap, AT91_PMC_PCR,
		     (gck->id & AT91_PMC_PCR_PID_MASK));
	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
			   AT91_PMC_PCR_CMD);
	regmap_write(gck->regmap, gck->layout->offset,
		     (gck->id & gck->layout->pid_mask));
	regmap_update_bits(gck->regmap, gck->layout->offset,
			   gck->layout->cmd | AT91_PMC_PCR_GCKEN,
			   gck->layout->cmd);
	spin_unlock_irqrestore(gck->lock, flags);
}

@@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw)
	unsigned int status;

	spin_lock_irqsave(gck->lock, flags);
	regmap_write(gck->regmap, AT91_PMC_PCR,
		     (gck->id & AT91_PMC_PCR_PID_MASK));
	regmap_read(gck->regmap, AT91_PMC_PCR, &status);
	regmap_write(gck->regmap, gck->layout->offset,
		     (gck->id & gck->layout->pid_mask));
	regmap_read(gck->regmap, gck->layout->offset, &status);
	spin_unlock_irqrestore(gck->lock, flags);

	return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
@@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck)
	unsigned long flags;

	spin_lock_irqsave(gck->lock, flags);
	regmap_write(gck->regmap, AT91_PMC_PCR,
		     (gck->id & AT91_PMC_PCR_PID_MASK));
	regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
	regmap_write(gck->regmap, gck->layout->offset,
		     (gck->id & gck->layout->pid_mask));
	regmap_read(gck->regmap, gck->layout->offset, &tmp);
	spin_unlock_irqrestore(gck->lock, flags);

	gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
					>> AT91_PMC_PCR_GCKCSS_OFFSET;
	gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
					>> AT91_PMC_PCR_GCKDIV_OFFSET;
	gck->parent_id = field_get(gck->layout->gckcss_mask, tmp);
	gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp);
}

struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
			    const struct clk_pcr_layout *layout,
			    const char *name, const char **parent_names,
			    u8 num_parents, u8 id, bool pll_audio,
			    const struct clk_range *range)
@@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
	gck->lock = lock;
	gck->range = *range;
	gck->audio_pll_allowed = pll_audio;
	gck->layout = layout;

	clk_generated_startup(gck);
	hw = &gck->hw;
+2 −1
Original line number Diff line number Diff line
@@ -154,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
		     id == GCK_ID_CLASSD))
			pll_audio = true;

		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
						 &dt_pcr_layout, name,
						 parent_names, num_parents,
						 id, pll_audio, &range);
		if (IS_ERR(hw))
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,

struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
			    const struct clk_pcr_layout *layout,
			    const char *name, const char **parent_names,
			    u8 num_parents, u8 id, bool pll_audio,
			    const struct clk_range *range);
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
	parent_names[5] = "audiopll_pmcck";
	for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
						 &sama5d2_pcr_layout,
						 sama5d2_gck[i].n,
						 parent_names, 6,
						 sama5d2_gck[i].id,
+1 −6
Original line number Diff line number Diff line
@@ -187,13 +187,8 @@

#define AT91_PMC_PCR		0x10c			/* Peripheral Control Register [some SAM9 and SAMA5] */
#define		AT91_PMC_PCR_PID_MASK		0x3f
#define		AT91_PMC_PCR_GCKCSS_OFFSET	8
#define		AT91_PMC_PCR_GCKCSS_MASK	(0x7  << AT91_PMC_PCR_GCKCSS_OFFSET)
#define		AT91_PMC_PCR_GCKCSS(n)		((n)  << AT91_PMC_PCR_GCKCSS_OFFSET)	/* GCK Clock Source Selection */
#define		AT91_PMC_PCR_CMD		(0x1  <<  12)				/* Command (read=0, write=1) */
#define		AT91_PMC_PCR_GCKDIV_OFFSET	20
#define		AT91_PMC_PCR_GCKDIV_MASK	(0xff  << AT91_PMC_PCR_GCKDIV_OFFSET)
#define		AT91_PMC_PCR_GCKDIV(n)		((n)  << AT91_PMC_PCR_GCKDIV_OFFSET)	/* Generated Clock Divisor Value */
#define		AT91_PMC_PCR_GCKDIV_MASK	GENMASK(27, 20)
#define		AT91_PMC_PCR_EN			(0x1  <<  28)				/* Enable */
#define		AT91_PMC_PCR_GCKEN		(0x1  <<  29)				/* GCK Enable */