| /* |
| * Copyright (c) 2014 Samsung Electronics Co., Ltd. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This file contains the utility functions for composite clocks. |
| */ |
| |
| #ifndef __SAMSUNG_CLK_COMPOSITE_H |
| #define __SAMSUNG_CLK_COMPOSITE_H |
| |
| #include <linux/clk.h> |
| #include <linux/clkdev.h> |
| #include <linux/clk-provider.h> |
| #include <linux/io.h> |
| |
| /* |
| * struct samsung_clk_provider: information about clock provider |
| * @reg_base: virtual address for the register base. |
| * @clk_data: holds clock related data like clk* and number of clocks. |
| * @lock: maintains exclusion bwtween callbacks for a given clock-provider. |
| */ |
| struct samsung_clk_provider { |
| void __iomem *reg_base; |
| struct clk_onecell_data clk_data; |
| spinlock_t lock; |
| }; |
| |
| /* |
| * struct samsung_clk_reg_dump: register dump of clock controller registers. |
| * @offset: clock register offset from the controller base address. |
| * @value: the value to be register at offset. |
| */ |
| struct samsung_clk_reg_dump { |
| unsigned long offset; |
| u32 value; |
| }; |
| |
| /* |
| * struct samsung_fixed_rate_clock: information about fixed-rate clock |
| * @id: platform specific id of the clock. |
| * @name: name of this fixed-rate clock. |
| * @parent_name: optional parent clock name. |
| * @flags: optional fixed-rate clock flags. |
| * @fixed-rate: fixed clock rate of this clock. |
| */ |
| struct samsung_fixed_rate { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long flags; |
| unsigned long fixed_rate; |
| }; |
| |
| #define FRATE(_id, cname, pname, f, frate) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parent_name = pname, \ |
| .flags = f, \ |
| .fixed_rate = frate, \ |
| } |
| |
| extern void __init samsung_register_fixed_rate( |
| struct samsung_clk_provider *ctx, |
| struct samsung_fixed_rate *list, |
| unsigned int nr_clk); |
| /* |
| * struct samsung_fixed_factor_clock: information about fixed-factor clock |
| * @id: platform specific id of the clock. |
| * @name: name of this fixed-factor clock. |
| * @parent_name: parent clock name. |
| * @mult: fixed multiplication factor. |
| * @div: fixed division factor. |
| * @flags: optional fixed-factor clock flags. |
| */ |
| struct samsung_fixed_factor { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long mult; |
| unsigned long div; |
| unsigned long flags; |
| }; |
| |
| #define FFACTOR(_id, cname, pname, m, d, f) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parent_name = pname, \ |
| .mult = m, \ |
| .div = d, \ |
| .flags = f, \ |
| } |
| |
| extern void __init samsung_register_fixed_factor( |
| struct samsung_clk_provider *ctx, |
| struct samsung_fixed_factor *list, |
| unsigned int nr_clk); |
| |
| /* |
| * PLL145xx Clock Type: PLL1450x, PLL1451x, PLL1452x |
| * Maximum lock time can be 150 * Pdiv cycles |
| */ |
| #define PLL145XX_LOCK_FACTOR (150) |
| #define PLL145XX_MDIV_MASK (0x3FF) |
| #define PLL145XX_PDIV_MASK (0x03F) |
| #define PLL145XX_SDIV_MASK (0x007) |
| #define PLL145XX_LOCKED_MASK (0x1) |
| #define PLL145XX_MDIV_SHIFT (16) |
| #define PLL145XX_PDIV_SHIFT (8) |
| #define PLL145XX_SDIV_SHIFT (0) |
| #define PLL145XX_LOCKED_SHIFT (29) |
| |
| /* |
| * PLL1460X Clock Type |
| * Maximum lock time can be 3000 * Pdiv cycles |
| */ |
| #define PLL1460X_LOCK_FACTOR (3000) |
| #define PLL1460X_MDIV_MASK (0x03FF) |
| #define PLL1460X_PDIV_MASK (0x003F) |
| #define PLL1460X_SDIV_MASK (0x0007) |
| #define PLL1460X_KDIV_MASK (0xFFFF) |
| #define PLL1460X_LOCKED_MASK (0x1) |
| #define PLL1460X_MDIV_SHIFT (16) |
| #define PLL1460X_PDIV_SHIFT (8) |
| #define PLL1460X_SDIV_SHIFT (0) |
| #define PLL1460X_KDIV_SHIFT (0) |
| #define PLL1460X_LOCKED_SHIFT (29) |
| |
| /* |
| * PLL255xx Clock Type : PLL2551x, PLL2555x |
| * Maximum lock time can be 200 * Pdiv cycles |
| */ |
| #define PLL255XX_LOCK_FACTOR (200) |
| #define PLL255XX_MDIV_MASK (0x3FF) |
| #define PLL255XX_PDIV_MASK (0x3F) |
| #define PLL255XX_SDIV_MASK (0x7) |
| #define PLL255XX_LOCKED_MASK (0x1) |
| #define PLL255XX_MDIV_SHIFT (12) |
| #define PLL255XX_PDIV_SHIFT (4) |
| #define PLL255XX_SDIV_SHIFT (0) |
| #define PLL255XX_LOCKED_SHIFT (29) |
| |
| /* |
| * PLL2650X Clock Type |
| * Maximum lock time can be 3000 * Pdiv cycles |
| */ |
| #define PLL2650X_LOCK_FACTOR (3000) |
| #define PLL2650X_MDIV_MASK (0x01FF) |
| #define PLL2650X_PDIV_MASK (0x003F) |
| #define PLL2650X_SDIV_MASK (0x0007) |
| #define PLL2650X_KDIV_MASK (0xFFFF) |
| #define PLL2650X_LOCKED_MASK (0x1) |
| #define PLL2650X_MDIV_SHIFT (12) |
| #define PLL2650X_PDIV_SHIFT (4) |
| #define PLL2650X_SDIV_SHIFT (0) |
| #define PLL2650X_KDIV_SHIFT (0) |
| #define PLL2650X_LOCKED_SHIFT (29) |
| |
| enum pll_type { |
| pll_1450x = 0, |
| pll_1451x, |
| pll_1452x, |
| pll_1460x, |
| pll_2551x, |
| pll_2555x, |
| pll_2650x, |
| }; |
| |
| struct samsung_pll_rate_table { |
| long rate; |
| unsigned int pdiv; |
| unsigned int mdiv; |
| unsigned int sdiv; |
| unsigned int kdiv; |
| }; |
| |
| #define PLL_BYPASS BIT(0) |
| #define CHK_ON_CHANGING BIT(7) |
| /* |
| * struct samsung_composite_pll: information about composite-pll clocks |
| * @id: id of the clock for binding with device tree. |
| * @name: name of this pll clock. |
| * @type: type of this pll clock. |
| * @lock_reg: register for locking pll. |
| * @con_reg: configuration register for pll. |
| * @enable_reg: it can be different whether pll can be gated or only bypassed. |
| * @enable_bit: bit index for en/disable pll. |
| * @sel_reg: composite-pll has ctrl-mux. when disabled, it is set by 0. |
| * @sel_bit: bit index for ctrl-mux. |
| * @stat_reg: when sel_reg is set, status register must be checked. |
| * @stat_bit: bit index for status register. |
| * @rate_table: available pll output ratio table. |
| * @alias: support alias for this clock. |
| */ |
| struct samsung_composite_pll { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| enum pll_type type; |
| void __iomem *lock_reg; |
| void __iomem *con_reg; |
| void __iomem *enable_reg; |
| unsigned int enable_bit; |
| void __iomem *sel_reg; |
| unsigned int sel_bit; |
| void __iomem *stat_reg; |
| unsigned int stat_bit; |
| const struct samsung_pll_rate_table *rate_table; |
| unsigned int rate_count; |
| unsigned int pll_flag; |
| u8 flag; |
| const char *alias; |
| }; |
| |
| #define PLL(_id, cname, _type, lock, con, en, enbit, sel, selbit, stat, statbit, rtable, pf, f, a) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .type = _type, \ |
| .lock_reg = lock, \ |
| .con_reg = con, \ |
| .enable_reg = en, \ |
| .enable_bit = enbit, \ |
| .sel_reg = sel, \ |
| .sel_bit = selbit, \ |
| .stat_reg = stat, \ |
| .stat_bit = statbit, \ |
| .rate_table = rtable, \ |
| .rate_count = 0, \ |
| .pll_flag = pf, \ |
| .flag = f, \ |
| .alias = a, \ |
| } |
| |
| extern void samsung_register_comp_pll( |
| struct samsung_clk_provider *ctx, |
| struct samsung_composite_pll *pll_list, |
| unsigned int nr_pll); |
| |
| #define PNAME(x) static const char *x[] |
| /* |
| * struct samsung_composite_mux: information about composite-mux clocks |
| * @id: id of the clock for binding with device tree. |
| * @name: name of this mux clock. |
| * @parents: array of parent clocks. |
| * @num_parents: number of parent clocks. |
| * @sel_reg: register for mux selection. |
| * @sel_bit: bit index for sel_reg. |
| * @sel_width: different by number of parent clocks. |
| * @stat_reg: status must be checked when changing parent. |
| * @stat_bit: bit index for status register. |
| * @stat_width: different by number of parent clocks. |
| * @flag: optional flag for clock. |
| * @alias: optional name. recommend no more than 15 characters. |
| */ |
| struct samsung_composite_mux { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const char **parents; |
| unsigned int num_parents; |
| void __iomem *sel_reg; |
| unsigned int sel_bit; |
| unsigned int sel_width; |
| void __iomem *stat_reg; |
| unsigned int stat_bit; |
| unsigned int stat_width; |
| unsigned int flag; |
| const char *alias; |
| spinlock_t *lock; |
| }; |
| |
| #define MUX(_id, cname, pnames, sel, selbit, selwid, stat, statbit, statwid, f, a) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parents = pnames, \ |
| .num_parents = ARRAY_SIZE(pnames), \ |
| .sel_reg = sel, \ |
| .sel_bit = selbit, \ |
| .sel_width = selwid, \ |
| .stat_reg = stat, \ |
| .stat_bit = statbit, \ |
| .stat_width = statwid, \ |
| .flag = f, \ |
| .alias = a, \ |
| } |
| |
| extern void samsung_register_comp_mux( |
| struct samsung_clk_provider *ctx, |
| struct samsung_composite_mux *mux_list, |
| unsigned int nr_mux); |
| |
| /* |
| * struct samsung_composite_divider: information about composite-divider clocks |
| * @id: id of the clock for binding with device tree. |
| * @name: name of this divider clock. |
| * @parent_name: name of parent clock. |
| * @rate_reg: register for ratio selection. |
| * @rate_bit: bit index for rate_reg. |
| * @rate_width: can be different by bit index. |
| * @stat_reg: status must be checked when changing ratio. |
| * @stat_bit: bit index for status register. |
| * @stat_width: can be different by bit index. |
| * @flag: flag for clock. |
| * @alias: optional name. recommend no more than 15 characters. |
| */ |
| struct samsung_composite_divider { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const char *parent_name; |
| void __iomem *rate_reg; |
| unsigned int rate_bit; |
| unsigned int rate_width; |
| void __iomem *stat_reg; |
| unsigned int stat_bit; |
| unsigned int stat_width; |
| unsigned int flag; |
| const char *alias; |
| spinlock_t *lock; |
| }; |
| |
| #define DIV(_id, cname, pname, rate, ratebit, ratewid, stat, statbit, statwid, f, a) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parent_name = pname, \ |
| .rate_reg = rate, \ |
| .rate_bit = ratebit, \ |
| .rate_width = ratewid, \ |
| .stat_reg = stat, \ |
| .stat_bit = statbit, \ |
| .stat_width = statwid, \ |
| .flag = f, \ |
| .alias = a, \ |
| } |
| |
| extern void samsung_register_comp_divider(struct samsung_clk_provider *ctx, |
| struct samsung_composite_divider *div_list, unsigned int nr_div); |
| |
| #define CLK_GATE_ENABLE BIT(20) |
| #define CLK_ON_CHANGING BIT(7) |
| /* |
| * struct samsung_gate: information about gate clocks |
| * @id: id of the clock for binding with device tree. |
| * @name: |
| * @parent_name: |
| * @reg: |
| * @bit: |
| * @flag: |
| * @alias: |
| */ |
| struct samsung_gate { |
| unsigned int id; |
| const char *name; |
| const char *parent_name; |
| void __iomem *reg; |
| u8 bit; |
| unsigned int flag; |
| const char *alias; |
| }; |
| |
| #define GATE(_id, cname, pname, r, b, f, a) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parent_name = pname, \ |
| .reg = r, \ |
| .bit = b, \ |
| .flag = f, \ |
| .alias = a, \ |
| } |
| |
| extern void __init samsung_register_gate( |
| struct samsung_clk_provider *ctx, |
| struct samsung_gate *gate_list, |
| unsigned int nr_gate); |
| |
| struct clk_samsung_usermux { |
| struct clk_hw hw; |
| void __iomem *sel_reg; |
| u8 sel_bit; |
| void __iomem *stat_reg; |
| u8 stat_bit; |
| u8 flag; |
| spinlock_t *lock; |
| }; |
| |
| /* |
| * struct samsung_composite_usermux: information about usermux clocks |
| * @id: id of the clock for binding with device tree. |
| * @name: name of this usermux clock. |
| * @parent_name: name of parent clock. |
| * @sel_reg: register for usermux selection. |
| * @sel_bit: bit index for sel_reg. |
| * @stat_reg: status must be checked when changing parent. |
| * @stat_bit: bit index for status register. |
| * @flag: optional flag for clock. |
| * @alias: optional name. recommend no more than 15 characters. |
| */ |
| struct samsung_usermux { |
| unsigned int id; |
| const char *name; |
| const char *parent_name; |
| void __iomem *sel_reg; |
| u8 sel_bit; |
| void __iomem *stat_reg; |
| u8 stat_bit; |
| u8 flag; |
| const char *alias; |
| }; |
| |
| #define USERMUX(_id, cname, pname, sel, selbit, stat, statbit, f, a) \ |
| { \ |
| .id = _id, \ |
| .name = cname, \ |
| .parent_name = pname, \ |
| .sel_reg = sel, \ |
| .sel_bit = selbit, \ |
| .stat_reg = stat, \ |
| .stat_bit = statbit, \ |
| .flag = f, \ |
| .alias = a, \ |
| } |
| |
| extern void __init samsung_register_usermux( |
| struct samsung_clk_provider *ctx, |
| struct samsung_usermux *list, |
| unsigned int nr_usermux); |
| |
| #define VCLK_DFS BIT(1) |
| #define VCLK_DFS_SWITCH BIT(2) |
| #define VCLK_GATE BIT(3) |
| #define VCLK_QCH_EN BIT(4) |
| #define VCLK_QCH_DIS BIT(5) |
| |
| /* |
| * struct init_vclk: initial information for virtual clocks |
| * @id: id of the clock for binding with device tree. |
| * @calid: id of the clock for calling cal. |
| * @name: name of this virtual clock. |
| * @flags: optional flag for clock. |
| * @vclk_flags: optional flag for only virtual clock. |
| * @alias: optional name. recommend no more than 15 characters. |
| */ |
| struct init_vclk{ |
| unsigned int id; |
| unsigned int calid; |
| const char *name; |
| const char *parent; |
| u8 flags; |
| u8 vclk_flags; |
| const char *alias; |
| }; |
| |
| struct samsung_vclk { |
| struct clk_hw hw; |
| unsigned int id; |
| u8 flags; |
| spinlock_t *lock; |
| }; |
| |
| #define VCLK(_id, _calid, _name, f, vf, a) \ |
| { \ |
| .id = _id, \ |
| .calid = _calid, \ |
| .name = _name, \ |
| .flags = f, \ |
| .vclk_flags = vf, \ |
| .alias = a, \ |
| } |
| |
| #define HWACG_VCLK(_id, _calid, _name, _parent, f, vf, a) \ |
| { \ |
| .id = _id, \ |
| .calid = _calid, \ |
| .name = _name, \ |
| .parent = _parent, \ |
| .flags = f, \ |
| .vclk_flags = vf, \ |
| .alias = a, \ |
| } |
| |
| extern void __init samsung_register_vclk(struct samsung_clk_provider *ctx, |
| struct init_vclk *list, unsigned int nr_vclk); |
| |
| extern struct samsung_clk_provider *__init samsung_clk_init( |
| struct device_node *np, void __iomem *base, |
| unsigned long nr_clks); |
| |
| extern void __init samsung_clk_of_add_provider(struct device_node *np, |
| struct samsung_clk_provider *ctx); |
| |
| extern void __init samsung_register_of_fixed_ext( |
| struct samsung_clk_provider *ctx, |
| struct samsung_fixed_rate *fixed_rate_clk, |
| unsigned int nr_fixed_rate_clk, |
| struct of_device_id *clk_matches); |
| |
| extern void samsung_clk_save(void __iomem *base, |
| struct samsung_clk_reg_dump *rd, |
| unsigned int num_regs); |
| extern void samsung_clk_restore(void __iomem *base, |
| const struct samsung_clk_reg_dump *rd, |
| unsigned int num_regs); |
| extern struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( |
| const unsigned long *rdump, |
| unsigned long nr_rdump); |
| |
| #endif /* __SAMSUNG_CLK_COMPOSITE_H */ |