From 61598093bbdd283a7edc367d900f223070ead8d2 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:03 +0000 Subject: [PATCH] add ax88772C AX88772C_eeprom_tools --- kernel/drivers/clk/at91/clk-generated.c | 180 +++++++++++++++++++++-------------------------------------- 1 files changed, 65 insertions(+), 115 deletions(-) diff --git a/kernel/drivers/clk/at91/clk-generated.c b/kernel/drivers/clk/at91/clk-generated.c index 66c7dde..fe772ba 100644 --- a/kernel/drivers/clk/at91/clk-generated.c +++ b/kernel/drivers/clk/at91/clk-generated.c @@ -1,16 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2015 Atmel Corporation, * Nicolas Ferre <nicolas.ferre@atmel.com> * * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ +#include <linux/bitfield.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/clk/at91_pmc.h> @@ -20,28 +16,19 @@ #include "pmc.h" -#define PERIPHERAL_MAX 64 -#define PERIPHERAL_ID_MIN 2 - -#define GENERATED_SOURCE_MAX 6 #define GENERATED_MAX_DIV 255 - -#define GCK_ID_SSC0 43 -#define GCK_ID_SSC1 44 -#define GCK_ID_I2S0 54 -#define GCK_ID_I2S1 55 -#define GCK_ID_CLASSD 59 -#define GCK_INDEX_DT_AUDIO_PLL 5 struct clk_generated { struct clk_hw hw; struct regmap *regmap; struct clk_range range; spinlock_t *lock; + u32 *mux_table; u32 id; u32 gckdiv; + const struct clk_pcr_layout *layout; u8 parent_id; - bool audio_pll_allowed; + int chg_pid; }; #define to_clk_generated(hw) \ @@ -56,14 +43,14 @@ __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; @@ -75,11 +62,11 @@ 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); } @@ -90,12 +77,12 @@ 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; + return !!(status & AT91_PMC_PCR_GCKEN); } static unsigned long @@ -119,9 +106,13 @@ tmp_rate = parent_rate; else tmp_rate = parent_rate / div; + + if (tmp_rate < req->min_rate || tmp_rate > req->max_rate) + return; + tmp_diff = abs(req->rate - tmp_rate); - if (*best_diff < 0 || *best_diff > tmp_diff) { + if (*best_diff < 0 || *best_diff >= tmp_diff) { *best_rate = tmp_rate; *best_diff = tmp_diff; req->best_parent_rate = parent_rate; @@ -141,7 +132,16 @@ int i; u32 div; - for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) { + /* do not look for a rate that is outside of our range */ + if (gck->range.max && req->rate > gck->range.max) + req->rate = gck->range.max; + if (gck->range.min && req->rate < gck->range.min) + req->rate = gck->range.min; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + if (gck->chg_pid == i) + continue; + parent = clk_hw_get_parent_by_index(hw, i); if (!parent) continue; @@ -173,16 +173,17 @@ * that the only clks able to modify gck rate are those of audio IPs. */ - if (!gck->audio_pll_allowed) + if (gck->chg_pid < 0) goto end; - parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL); + parent = clk_hw_get_parent_by_index(hw, gck->chg_pid); if (!parent) goto end; for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { req_parent.rate = req->rate * div; - __clk_determine_rate(parent, &req_parent); + if (__clk_determine_rate(parent, &req_parent)) + continue; clk_generated_best_diff(req, parent, req_parent.rate, div, &best_diff, &best_rate); @@ -196,8 +197,8 @@ __clk_get_name((req->best_parent_hw)->clk), req->best_parent_rate); - if (best_rate < 0) - return best_rate; + if (best_rate < 0 || (gck->range.max && best_rate > gck->range.max)) + return -EINVAL; req->rate = best_rate; return 0; @@ -211,7 +212,11 @@ if (index >= clk_hw_get_num_parents(hw)) return -EINVAL; - gck->parent_id = index; + if (gck->mux_table) + gck->parent_id = clk_mux_index_to_val(gck->mux_table, 0, index); + else + gck->parent_id = index; + return 0; } @@ -270,25 +275,25 @@ 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); } -static struct clk_hw * __init +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) + u32 *mux_table, u8 num_parents, u8 id, + const struct clk_range *range, + int chg_pid) { struct clk_generated *gck; - struct clk_init_data init = {}; + struct clk_init_data init; struct clk_hw *hw; int ret; @@ -300,15 +305,18 @@ init.ops = &generated_ops; init.parent_names = parent_names; init.num_parents = num_parents; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | - CLK_SET_RATE_PARENT; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + if (chg_pid >= 0) + init.flags |= CLK_SET_RATE_PARENT; gck->id = id; gck->hw.init = &init; gck->regmap = regmap; gck->lock = lock; gck->range = *range; - gck->audio_pll_allowed = pll_audio; + gck->chg_pid = chg_pid; + gck->layout = layout; + gck->mux_table = mux_table; clk_generated_startup(gck); hw = &gck->hw; @@ -322,61 +330,3 @@ return hw; } - -static void __init of_sama5d2_clk_generated_setup(struct device_node *np) -{ - int num; - u32 id; - const char *name; - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[GENERATED_SOURCE_MAX]; - struct device_node *gcknp; - struct clk_range range = CLK_RANGE(0, 0); - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - num = of_get_child_count(np); - if (!num || num > PERIPHERAL_MAX) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, gcknp) { - bool pll_audio = false; - - if (of_property_read_u32(gcknp, "reg", &id)) - continue; - - if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = gcknp->name; - - of_at91_get_clk_range(gcknp, "atmel,clk-output-range", - &range); - - if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") && - (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 || - id == GCK_ID_CLASSD)) - pll_audio = true; - - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, - parent_names, num_parents, - id, pll_audio, &range); - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); - } -} -CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", - of_sama5d2_clk_generated_setup); -- Gitblit v1.6.2