diff options
Diffstat (limited to 'include/linux/clk')
| -rw-r--r-- | include/linux/clk/gdsc.h | 22 | ||||
| -rw-r--r-- | include/linux/clk/msm-clk-provider.h | 270 | ||||
| -rw-r--r-- | include/linux/clk/msm-clk.h | 138 | ||||
| -rw-r--r-- | include/linux/clk/msm-clock-generic.h | 310 |
4 files changed, 740 insertions, 0 deletions
diff --git a/include/linux/clk/gdsc.h b/include/linux/clk/gdsc.h new file mode 100644 index 000000000000..b012ed06d3f4 --- /dev/null +++ b/include/linux/clk/gdsc.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __GDSC_H +#define __GDSC_H + +#include <linux/regulator/consumer.h> + +/* Allow the clock memories to be turned off */ +void gdsc_allow_clear_retention(struct regulator *regulator); + +#endif diff --git a/include/linux/clk/msm-clk-provider.h b/include/linux/clk/msm-clk-provider.h new file mode 100644 index 000000000000..2fa8916ad356 --- /dev/null +++ b/include/linux/clk/msm-clk-provider.h @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MSM_CLK_PROVIDER_H +#define __MSM_CLK_PROVIDER_H + +#include <linux/types.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> +#include <linux/seq_file.h> +#include <linux/clk/msm-clk.h> + +#if defined(CONFIG_COMMON_CLK_MSM) +/* + * Bit manipulation macros + */ +#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) +#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) + +/* + * Halt/Status Checking Mode Macros + */ +#define HALT 0 /* Bit pol: 1 = halted */ +#define NOCHECK 1 /* No bit to check, do nothing */ +#define HALT_VOTED 2 /* Bit pol: 1 = halted; delay on disable */ +#define ENABLE 3 /* Bit pol: 1 = running */ +#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */ +#define DELAY 5 /* No bit to check, just delay */ + +struct clk_register_data { + char *name; + u32 offset; +}; +#ifdef CONFIG_DEBUG_FS +void clk_debug_print_hw(struct clk *clk, struct seq_file *f); +#else +static inline void clk_debug_print_hw(struct clk *clk, struct seq_file *f) {} +#endif + +#define CLK_WARN(clk, cond, fmt, ...) do { \ + clk_debug_print_hw(clk, NULL); \ + WARN(cond, "%s: " fmt, clk_name(clk), ##__VA_ARGS__); \ +} while (0) + +/** + * struct clk_vdd_class - Voltage scaling class + * @class_name: name of the class + * @regulator: array of regulators. + * @num_regulators: size of regulator array. Standard regulator APIs will be + used if this field > 0. + * @set_vdd: function to call when applying a new voltage setting. + * @vdd_uv: sorted 2D array of legal voltage settings. Indexed by level, then + regulator. + * @vdd_ua: sorted 2D array of legal cureent settings. Indexed by level, then + regulator. Optional parameter. + * @level_votes: array of votes for each level. + * @num_levels: specifies the size of level_votes array. + * @skip_handoff: do not vote for the max possible voltage during init + * @use_max_uV: use INT_MAX for max_uV when calling regulator_set_voltage + * This is useful when different vdd_class share same regulator. + * @cur_level: the currently set voltage level + * @lock: lock to protect this struct + */ +struct clk_vdd_class { + const char *class_name; + struct regulator **regulator; + int num_regulators; + int (*set_vdd)(struct clk_vdd_class *v_class, int level); + int *vdd_uv; + int *vdd_ua; + int *level_votes; + int num_levels; + bool skip_handoff; + bool use_max_uV; + unsigned long cur_level; + struct mutex lock; +}; + +#define DEFINE_VDD_CLASS(_name, _set_vdd, _num_levels) \ + struct clk_vdd_class _name = { \ + .class_name = #_name, \ + .set_vdd = _set_vdd, \ + .level_votes = (int [_num_levels]) {}, \ + .num_levels = _num_levels, \ + .cur_level = _num_levels, \ + .lock = __MUTEX_INITIALIZER(_name.lock) \ + } + +#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv, \ + _vdd_ua) \ + struct clk_vdd_class _name = { \ + .class_name = #_name, \ + .vdd_uv = _vdd_uv, \ + .vdd_ua = _vdd_ua, \ + .regulator = (struct regulator * [_num_regulators]) {}, \ + .num_regulators = _num_regulators, \ + .level_votes = (int [_num_levels]) {}, \ + .num_levels = _num_levels, \ + .cur_level = _num_levels, \ + .lock = __MUTEX_INITIALIZER(_name.lock) \ + } + +#define DEFINE_VDD_REGS_INIT(_name, _num_regulators) \ + struct clk_vdd_class _name = { \ + .class_name = #_name, \ + .regulator = (struct regulator * [_num_regulators]) {}, \ + .num_regulators = _num_regulators, \ + .lock = __MUTEX_INITIALIZER(_name.lock) \ + } + +enum handoff { + HANDOFF_ENABLED_CLK, + HANDOFF_DISABLED_CLK, +}; + +struct clk_ops { + int (*prepare)(struct clk *clk); + int (*enable)(struct clk *clk); + void (*disable)(struct clk *clk); + void (*unprepare)(struct clk *clk); + void (*enable_hwcg)(struct clk *clk); + void (*disable_hwcg)(struct clk *clk); + int (*in_hwcg_mode)(struct clk *clk); + enum handoff (*handoff)(struct clk *clk); + int (*reset)(struct clk *clk, enum clk_reset_action action); + int (*pre_set_rate)(struct clk *clk, unsigned long new_rate); + int (*set_rate)(struct clk *clk, unsigned long rate); + void (*post_set_rate)(struct clk *clk, unsigned long old_rate); + int (*set_max_rate)(struct clk *clk, unsigned long rate); + int (*set_flags)(struct clk *clk, unsigned flags); + unsigned long (*get_rate)(struct clk *clk); + long (*list_rate)(struct clk *clk, unsigned n); + int (*is_enabled)(struct clk *clk); + long (*round_rate)(struct clk *clk, unsigned long rate); + int (*set_parent)(struct clk *clk, struct clk *parent); + struct clk *(*get_parent)(struct clk *clk); + bool (*is_local)(struct clk *clk); + void __iomem *(*list_registers)(struct clk *clk, int n, + struct clk_register_data **regs, u32 *size); +}; + +/** + * struct clk + * @prepare_count: prepare refcount + * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count + * @count: enable refcount + * @lock: protects clk_enable()/clk_disable() path and @count + * @depends: non-direct parent of clock to enable when this clock is enabled + * @vdd_class: voltage scaling requirement class + * @fmax: maximum frequency in Hz supported at each voltage level + * @parent: the current source of this clock + * @opp_table_populated: tracks if the OPP table of this clock has been filled + */ +struct clk { + uint32_t flags; + struct clk_ops *ops; + const char *dbg_name; + struct clk *depends; + struct clk_vdd_class *vdd_class; + unsigned long *fmax; + int num_fmax; + unsigned long rate; + struct clk *parent; + struct clk_src *parents; + unsigned int num_parents; + + struct list_head children; + struct list_head siblings; + struct list_head list; + + unsigned count; + unsigned notifier_count; + spinlock_t lock; + unsigned prepare_count; + struct mutex prepare_lock; + + unsigned long init_rate; + bool always_on; + bool opp_table_populated; + + struct dentry *clk_dir; +}; + +#define CLK_INIT(name) \ + .lock = __SPIN_LOCK_UNLOCKED((name).lock), \ + .prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \ + .children = LIST_HEAD_INIT((name).children), \ + .siblings = LIST_HEAD_INIT((name).siblings), \ + .list = LIST_HEAD_INIT((name).list) + +bool is_rate_valid(struct clk *clk, unsigned long rate); +int vote_vdd_level(struct clk_vdd_class *vdd_class, int level); +int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level); +int __clk_pre_reparent(struct clk *c, struct clk *new, unsigned long *flags); +void __clk_post_reparent(struct clk *c, struct clk *old, unsigned long *flags); + +/* Register clocks with the MSM clock driver */ +int msm_clock_register(struct clk_lookup *table, size_t size); +int of_msm_clock_register(struct device_node *np, struct clk_lookup *table, + size_t size); + +int clock_rcgwr_init(struct platform_device *pdev); +int clock_rcgwr_disable(struct platform_device *pdev); + +extern struct clk dummy_clk; +extern struct clk_ops clk_ops_dummy; + +#define CLK_DUMMY(clk_name, clk_id, clk_dev, flags) { \ + .con_id = clk_name, \ + .dev_id = clk_dev, \ + .clk = &dummy_clk, \ + } + +#define DEFINE_CLK_DUMMY(name, _rate) \ + static struct fixed_clk name = { \ + .c = { \ + .dbg_name = #name, \ + .rate = _rate, \ + .ops = &clk_ops_dummy, \ + CLK_INIT(name.c), \ + }, \ + }; + +#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev } +#define CLK_LOOKUP_OF(con, _c, dev) { .con_id = con, .clk = &(&_c)->c, \ + .dev_id = dev, .of_idx = clk_##_c } +#define CLK_LIST(_c) { .clk = &(&_c)->c, .of_idx = clk_##_c } + +static inline bool is_better_rate(unsigned long req, unsigned long best, + unsigned long new) +{ + if (IS_ERR_VALUE(new)) + return false; + + return (req <= new && new < best) || (best < req && best < new); +} + +extern int of_clk_add_provider(struct device_node *np, + struct clk *(*clk_src_get)(struct of_phandle_args *args, + void *data), + void *data); +extern void of_clk_del_provider(struct device_node *np); + +static inline const char *clk_name(struct clk *c) +{ + if (IS_ERR_OR_NULL(c)) + return "(null)"; + return c->dbg_name; +}; +#endif /* CONFIG_COMMON_CLK_MSM */ +#endif diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h new file mode 100644 index 000000000000..8455fd776246 --- /dev/null +++ b/include/linux/clk/msm-clk.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2009, 2012-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __MACH_CLK_H +#define __MACH_CLK_H + +#include <linux/notifier.h> + +#if defined(CONFIG_COMMON_CLK_QCOM) +enum branch_mem_flags { + CLKFLAG_RETAIN_PERIPH, + CLKFLAG_NORETAIN_PERIPH, + CLKFLAG_RETAIN_MEM, + CLKFLAG_NORETAIN_MEM, + CLKFLAG_PERIPH_OFF_SET, + CLKFLAG_PERIPH_OFF_CLEAR, +}; + +#include <linux/clk.h> + +#elif defined(CONFIG_COMMON_CLK_MSM) +#define CLKFLAG_INVERT 0x00000001 +#define CLKFLAG_NOINVERT 0x00000002 +#define CLKFLAG_NONEST 0x00000004 +#define CLKFLAG_NORESET 0x00000008 +#define CLKFLAG_RETAIN_PERIPH 0x00000010 +#define CLKFLAG_NORETAIN_PERIPH 0x00000020 +#define CLKFLAG_RETAIN_MEM 0x00000040 +#define CLKFLAG_NORETAIN_MEM 0x00000080 +#define CLKFLAG_SKIP_HANDOFF 0x00000100 +#define CLKFLAG_MIN 0x00000400 +#define CLKFLAG_MAX 0x00000800 +#define CLKFLAG_INIT_DONE 0x00001000 +#define CLKFLAG_INIT_ERR 0x00002000 +#define CLKFLAG_NO_RATE_CACHE 0x00004000 +#define CLKFLAG_MEASURE 0x00008000 +#define CLKFLAG_EPROBE_DEFER 0x00010000 +#define CLKFLAG_PERIPH_OFF_SET 0x00020000 +#define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000 + +struct clk_lookup; +struct clk; + +enum clk_reset_action { + CLK_RESET_DEASSERT = 0, + CLK_RESET_ASSERT = 1 +}; + +struct clk_src { + struct clk *src; + int sel; +}; + +/* Rate is maximum clock rate in Hz */ +int clk_set_max_rate(struct clk *clk, unsigned long rate); + +/* Assert/Deassert reset to a hardware block associated with a clock */ +int clk_reset(struct clk *clk, enum clk_reset_action action); + +/* Set clock-specific configuration parameters */ +int clk_set_flags(struct clk *clk, unsigned long flags); + +/* returns the mux selection index associated with a particular parent */ +int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p); + +/* returns the mux selection index associated with a particular parent */ +int clk_get_parent_sel(struct clk *c, struct clk *parent); + +/** + * DOC: clk notifier callback types + * + * PRE_RATE_CHANGE - called immediately before the clk rate is changed, + * to indicate that the rate change will proceed. Drivers must + * immediately terminate any operations that will be affected by the + * rate change. Callbacks may either return NOTIFY_DONE, NOTIFY_OK, + * NOTIFY_STOP or NOTIFY_BAD. + * + * ABORT_RATE_CHANGE: called if the rate change failed for some reason + * after PRE_RATE_CHANGE. In this case, all registered notifiers on + * the clk will be called with ABORT_RATE_CHANGE. Callbacks must + * always return NOTIFY_DONE or NOTIFY_OK. + * + * POST_RATE_CHANGE - called after the clk rate change has successfully + * completed. Callbacks must always return NOTIFY_DONE or NOTIFY_OK. + * + */ +#define PRE_RATE_CHANGE BIT(0) +#define POST_RATE_CHANGE BIT(1) +#define ABORT_RATE_CHANGE BIT(2) + +/** + * struct msm_clk_notifier - associate a clk with a notifier + * @clk: struct clk * to associate the notifier with + * @notifier_head: a blocking_notifier_head for this clk + * @node: linked list pointers + * + * A list of struct clk_notifier is maintained by the notifier code. + * An entry is created whenever code registers the first notifier on a + * particular @clk. Future notifiers on that @clk are added to the + * @notifier_head. + */ +struct msm_clk_notifier { + struct clk *clk; + struct srcu_notifier_head notifier_head; + struct list_head node; +}; + +/** + * struct msm_clk_notifier_data - rate data to pass to the notifier callback + * @clk: struct clk * being changed + * @old_rate: previous rate of this clk + * @new_rate: new rate of this clk + * + * For a pre-notifier, old_rate is the clk's rate before this rate + * change, and new_rate is what the rate will be in the future. For a + * post-notifier, old_rate and new_rate are both set to the clk's + * current rate (this was done to optimize the implementation). + */ +struct msm_clk_notifier_data { + struct clk *clk; + unsigned long old_rate; + unsigned long new_rate; +}; + +int msm_clk_notif_register(struct clk *clk, struct notifier_block *nb); + +int msm_clk_notif_unregister(struct clk *clk, struct notifier_block *nb); + +#endif /* CONFIG_COMMON_CLK_MSM */ +#endif diff --git a/include/linux/clk/msm-clock-generic.h b/include/linux/clk/msm-clock-generic.h new file mode 100644 index 000000000000..d7186a363a3f --- /dev/null +++ b/include/linux/clk/msm-clock-generic.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MSM_CLOCK_GENERIC_H +#define __MSM_CLOCK_GENERIC_H + +#include <linux/clk/msm-clk-provider.h> +#include <linux/of.h> + +/** + * struct fixed_clk - fixed rate clock + * @c: clk + */ +struct fixed_clk { + struct clk c; +}; + +/* ==================== Mux clock ==================== */ + +struct mux_clk; + +struct clk_mux_ops { + int (*set_mux_sel)(struct mux_clk *clk, int sel); + int (*get_mux_sel)(struct mux_clk *clk); + + /* Optional */ + bool (*is_enabled)(struct mux_clk *clk); + int (*enable)(struct mux_clk *clk); + void (*disable)(struct mux_clk *clk); + void __iomem *(*list_registers)(struct mux_clk *clk, int n, + struct clk_register_data **regs, u32 *size); +}; + +#define MUX_SRC_LIST(...) \ + .parents = (struct clk_src[]){__VA_ARGS__}, \ + .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__})) + +#define MUX_REC_SRC_LIST(...) \ + .rec_parents = (struct clk * []){__VA_ARGS__}, \ + .num_rec_parents = ARRAY_SIZE(((struct clk * []){__VA_ARGS__})) + +struct mux_clk { + /* Parents in decreasing order of preference for obtaining rates. */ + struct clk_src *parents; + int num_parents; + /* Recursively search for the requested parent in rec_parents. */ + struct clk **rec_parents; + int num_rec_parents; + struct clk *safe_parent; + int safe_sel; + unsigned long safe_freq; + /* + * Before attempting a clk_round_rate on available sources, attempt a + * clk_get_rate on all those sources. If one of them is already at the + * necessary rate, that source will be used. + */ + bool try_get_rate; + struct clk_mux_ops *ops; + /* + * Set if you need the mux to try a new parent before falling back to + * the current parent. If the safe_parent field above is set, then the + * safe_sel intermediate source will only be used if we fall back to + * to the current parent during mux_set_rate. + */ + bool try_new_parent; + + /* Fields not used by helper function. */ + void *const __iomem *base; + u32 offset; + u32 en_offset; + u32 mask; + u32 shift; + u32 en_mask; + /* + * Set post divider for debug mux in order to divide the clock + * by post_div + 1. + */ + u32 post_div; + int low_power_sel; + void *priv; + + struct clk c; +}; + +static inline struct mux_clk *to_mux_clk(struct clk *c) +{ + return container_of(c, struct mux_clk, c); +} + +extern struct clk_ops clk_ops_gen_mux; + +/* ==================== Divider clock ==================== */ + +struct div_clk; + +struct clk_div_ops { + int (*set_div)(struct div_clk *clk, int div); + int (*get_div)(struct div_clk *clk); + bool (*is_enabled)(struct div_clk *clk); + int (*enable)(struct div_clk *clk); + void (*disable)(struct div_clk *clk); + void __iomem *(*list_registers)(struct div_clk *clk, int n, + struct clk_register_data **regs, u32 *size); +}; + +struct div_data { + unsigned int div; + unsigned int min_div; + unsigned int max_div; + unsigned long rate_margin; + /* + * Indicate whether this divider clock supports half-interger divider. + * If it is, all the min_div and max_div have been doubled. It means + * they are 2*N. + */ + bool is_half_divider; + /* + * Skip odd dividers since the hardware may not support them. + */ + bool skip_odd_div; + bool skip_even_div; + bool allow_div_one; + unsigned int cached_div; +}; + +struct div_clk { + struct div_data data; + + /* + * Some implementations may require the divider to be set to a "safe" + * value that allows reprogramming of upstream clocks without violating + * voltage constraints. + */ + unsigned long safe_freq; + + /* Optional */ + struct clk_div_ops *ops; + + /* Fields not used by helper function. */ + void *const __iomem *base; + u32 offset; + u32 mask; + u32 shift; + u32 en_mask; + void *priv; + struct clk c; +}; + +static inline struct div_clk *to_div_clk(struct clk *c) +{ + return container_of(c, struct div_clk, c); +} + +extern struct clk_ops clk_ops_div; +extern struct clk_ops clk_ops_slave_div; + +struct ext_clk { + struct clk c; + struct device *dev; + char *clk_id; +}; + +long parent_round_rate(struct clk *c, unsigned long rate); +unsigned long parent_get_rate(struct clk *c); +int parent_set_rate(struct clk *c, unsigned long rate); + +static inline struct ext_clk *to_ext_clk(struct clk *c) +{ + return container_of(c, struct ext_clk, c); +} + +extern struct clk_ops clk_ops_ext; + +#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \ +static struct div_clk clk_name = { \ + .data = { \ + .max_div = _div, \ + .min_div = _div, \ + .div = _div, \ + }, \ + .c = { \ + .parent = _parent, \ + .dbg_name = #clk_name, \ + .ops = &clk_ops_div, \ + CLK_INIT(clk_name.c), \ + } \ +} + +#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \ +static struct div_clk clk_name = { \ + .data = { \ + .max_div = _div, \ + .min_div = _div, \ + .div = _div, \ + }, \ + .c = { \ + .parent = _parent, \ + .dbg_name = #clk_name, \ + .ops = &clk_ops_slave_div, \ + CLK_INIT(clk_name.c), \ + } \ +} + +#define DEFINE_EXT_CLK(clk_name, _parent) \ +static struct ext_clk clk_name = { \ + .c = { \ + .parent = _parent, \ + .dbg_name = #clk_name, \ + .ops = &clk_ops_ext, \ + CLK_INIT(clk_name.c), \ + } \ +} + +/* ==================== Mux Div clock ==================== */ + +struct mux_div_clk; + +/* + * struct mux_div_ops + * the enable and disable ops are optional. + */ + +struct mux_div_ops { + int (*set_src_div)(struct mux_div_clk *, u32 src_sel, u32 div); + void (*get_src_div)(struct mux_div_clk *, u32 *src_sel, u32 *div); + int (*enable)(struct mux_div_clk *); + void (*disable)(struct mux_div_clk *); + bool (*is_enabled)(struct mux_div_clk *); + void __iomem *(*list_registers)(struct mux_div_clk *md, int n, + struct clk_register_data **regs, u32 *size); +}; + +/* + * struct mux_div_clk - combined mux/divider clock + * @priv + parameters needed by ops + * @safe_freq + when switching rates from A to B, the mux div clock will + instead switch from A -> safe_freq -> B. This allows the + mux_div clock to change rates while enabled, even if this + behavior is not supported by the parent clocks. + + If changing the rate of parent A also causes the rate of + parent B to change, then safe_freq must be defined. + + safe_freq is expected to have a source clock which is always + on and runs at only one rate. + * @parents + list of parents and mux indicies + * @ops + function pointers for hw specific operations + * @src_sel + the mux index which will be used if the clock is enabled. + * @try_get_rate + Set if you need the mux to directly jump to a source + that is at the desired rate currently. + * @force_enable_md + Set if the mux-div needs to be force enabled/disabled during + clk_enable/disable. + */ + +struct mux_div_clk { + /* Required parameters */ + struct mux_div_ops *ops; + struct div_data data; + struct clk_src *parents; + u32 num_parents; + + struct clk c; + + /* Internal */ + u32 src_sel; + + /* Optional parameters */ + void *priv; + void __iomem *base; + u32 div_mask; + u32 div_offset; + u32 div_shift; + u32 src_mask; + u32 src_offset; + u32 src_shift; + u32 en_mask; + u32 en_offset; + + u32 safe_div; + struct clk *safe_parent; + unsigned long safe_freq; + bool try_get_rate; + bool force_enable_md; +}; + +static inline struct mux_div_clk *to_mux_div_clk(struct clk *clk) +{ + return container_of(clk, struct mux_div_clk, c); +} + +extern struct clk_ops clk_ops_mux_div_clk; + +#endif |
