M7350/kernel/include/linux/clk/msm-clock-generic.h

306 lines
7.4 KiB
C
Raw Normal View History

2024-09-09 08:57:42 +00:00
/*
* Copyright (c) 2013-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 __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;
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