/* Perform any register operations required to enable the clock. */
void local_clk_enable_reg(unsigned id)
{
	struct clk_local *clk = &soc_clk_local_tbl[id];
	void *reg = clk->cc_reg;
	uint32_t reg_val;

	WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq),
		"Attempting to enable clock %d before setting its rate. "
		"Set the rate first!\n", id);

	/* Program the NS register, if applicable. NS registers are not
	 * set in the set_rate path because power can be saved by deferring
	 * the selection of a clocked source until the clock is enabled. */
	if (clk->ns_mask) {
		reg_val = readl(clk->ns_reg);
		reg_val &= ~(clk->ns_mask);
		reg_val |= (clk->current_freq->ns_val & clk->ns_mask);
		writel(reg_val, clk->ns_reg);
	}

	/* Enable MN counter, if applicable. */
	reg_val = readl(reg);
	if (clk->type == MND) {
		reg_val |= clk->current_freq->mnd_en_mask;
		writel(reg_val, reg);
	}
	/* Enable root. */
	if (clk->root_en_mask) {
		reg_val |= clk->root_en_mask;
		writel(reg_val, reg);
	}
	/* Enable branch. */
	if (clk->br_en_mask) {
		reg_val |= clk->br_en_mask;
		writel(reg_val, reg);
	}

	/* Wait for clock to enable before returning. */
	if (clk->halt_check == DELAY)
		udelay(HALT_CHECK_DELAY_US);
	else if (clk->halt_check == ENABLE || clk->halt_check == HALT
			|| clk->halt_check == ENABLE_VOTED
			|| clk->halt_check == HALT_VOTED) {
		int count;
		/* Use a memory barrier since some halt status registers are
		 * not within the same 1K segment as the branch/root enable
		 * registers. */
		mb();

		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */
		for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id)
					&& count > 0; count--)
			udelay(1);
		if (count == 0)
			pr_warning("%s: clock %d status stuck at 'off' (bit %d "
				   "of 0x%p).\n", __func__, id, clk->halt_bit,
				   clk->halt_reg);
	}
}
/* Perform any register operations required to enable the clock. */
void local_clk_disable_reg(unsigned id)
{
	struct clk_local *clk = &soc_clk_local_tbl[id];
	void *reg = clk->cc_reg;
	uint32_t reg_val;

	/* Disable branch. */
	reg_val = readl(reg);
	if (clk->br_en_mask) {
		reg_val &= ~(clk->br_en_mask);
		writel(reg_val, reg);
	}

	/* Wait for clock to disable before continuing. */
	if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED
				     || clk->halt_check == HALT_VOTED)
		udelay(HALT_CHECK_DELAY_US);
	else if (clk->halt_check == ENABLE || clk->halt_check == HALT) {
		int count;
		/* Use a memory barrier since some halt status registers are
		 * not within the same 1K segment as the branch/root enable
		 * registers. */
		mb();

		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */
		for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id)
					&& count > 0; count--)
			udelay(1);
		if (count == 0)
			pr_warning("%s: clock %d status stuck at 'on' (bit %d "
				   "of 0x%p).\n", __func__, id, clk->halt_bit,
				   clk->halt_reg);
	}

	/* Disable root. */
	if (clk->root_en_mask) {
		reg_val &= ~(clk->root_en_mask);
		writel(reg_val, reg);
	}
	/* Disable MN counter, if applicable. */
	if (clk->type == MND) {
		reg_val &= ~(clk->current_freq->mnd_en_mask);
		writel(reg_val, reg);
	}
	/* Program NS register to low-power value with an un-clocked or
	 * slowly-clocked source selected. */
	if (clk->ns_mask) {
		reg_val = readl(clk->ns_reg);
		reg_val &= ~(clk->ns_mask);
		reg_val |= (clk->freq_tbl->ns_val & clk->ns_mask);
		writel(reg_val, clk->ns_reg);
	}
}
/* Perform any register operations required to enable the clock. */
void local_clk_enable_reg(unsigned id)
{
	struct clk_local *clk = &soc_clk_local_tbl[id];
	void *reg = clk->cc_reg;
	uint32_t reg_val;

	WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq),
		"Attempting to enable clock %d before setting its rate. "
		"Set the rate first!\n", id);

	/* Enable MN counter, if applicable. */
	reg_val = readl_relaxed(reg);
	if (clk->type == MND) {
		reg_val |= clk->current_freq->mnd_en_mask;
		writel_relaxed(reg_val, reg);
	}
	/* Enable root. */
	if (clk->root_en_mask) {
		reg_val |= clk->root_en_mask;
		writel_relaxed(reg_val, reg);
	}
	/* Enable branch. */
	if (clk->br_en_mask) {
		reg_val |= clk->br_en_mask;
		writel_relaxed(reg_val, reg);
	}

	/*
	 * Use a memory barrier since some halt status registers are
	 * not within the same 1K segment as the branch/root enable
	 * registers.  It's also needed in the udelay() case to ensure
	 * the delay starts after the branch enable.
	 */
	mb();

	/* Wait for clock to enable before returning. */
	if (clk->halt_check == DELAY)
		udelay(HALT_CHECK_DELAY_US);
	else if (clk->halt_check == ENABLE || clk->halt_check == HALT
			|| clk->halt_check == ENABLE_VOTED
			|| clk->halt_check == HALT_VOTED) {
		int count;

		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */
		for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id)
					&& count > 0; count--)
			udelay(1);
		if (count == 0)
			pr_warning("%s: clock %d status bit stuck off\n",
				   __func__, id);
	}
}
/* Perform any register operations required to enable the clock. */
void local_clk_disable_reg(unsigned id)
{
	struct clk_local *clk = &soc_clk_local_tbl[id];
	void *reg = clk->cc_reg;
	uint32_t reg_val;

	/* Disable branch. */
	reg_val = readl_relaxed(reg);
	if (clk->br_en_mask) {
		reg_val &= ~(clk->br_en_mask);
		writel_relaxed(reg_val, reg);
	}

	/*
	 * Use a memory barrier since some halt status registers are
	 * not within the same K segment as the branch/root enable
	 * registers.  It's also needed in the udelay() case to ensure
	 * the delay starts after the branch disable.
	 */
	mb();

	/* Wait for clock to disable before continuing. */
	if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED
				     || clk->halt_check == HALT_VOTED)
		udelay(HALT_CHECK_DELAY_US);
	else if (clk->halt_check == ENABLE || clk->halt_check == HALT) {
		int count;

		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */
		for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id)
					&& count > 0; count--)
			udelay(1);
		if (count == 0)
			pr_warning("%s: clock %d status bit stuck on\n",
				   __func__, id);
	}

	/* Disable root. */
	if (clk->root_en_mask) {
		reg_val &= ~(clk->root_en_mask);
		writel_relaxed(reg_val, reg);
	}
	/* Disable MN counter, if applicable. */
	if (clk->type == MND) {
		reg_val &= ~(clk->current_freq->mnd_en_mask);
		writel_relaxed(reg_val, reg);
	}
}