root/drivers/clk/sprd/div.h
/* SPDX-License-Identifier: GPL-2.0 */
//
// Spreadtrum divider clock driver
//
// Copyright (C) 2017 Spreadtrum, Inc.
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>

#ifndef _SPRD_DIV_H_
#define _SPRD_DIV_H_

#include "common.h"

/**
 * struct sprd_div_internal - Internal divider description
 * @shift: Bit offset of the divider in its register
 * @width: Width of the divider field in its register
 *
 * That structure represents a single divider, and is meant to be
 * embedded in other structures representing the various clock
 * classes.
 */
struct sprd_div_internal {
        s32     offset;
        u8      shift;
        u8      width;
};

#define _SPRD_DIV_CLK(_offset, _shift, _width)  \
        {                               \
                .offset = _offset,      \
                .shift  = _shift,       \
                .width  = _width,       \
        }

struct sprd_div {
        struct sprd_div_internal        div;
        struct sprd_clk_common  common;
};

#define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _offset, \
                                _shift, _width, _flags, _fn)            \
        struct sprd_div _struct = {                                     \
                .div    = _SPRD_DIV_CLK(_offset, _shift, _width),       \
                .common = {                                             \
                        .regmap         = NULL,                         \
                        .reg            = _reg,                         \
                        .hw.init        = _fn(_name, _parent,           \
                                              &sprd_div_ops, _flags),   \
                }                                                       \
        }

#define SPRD_DIV_CLK(_struct, _name, _parent, _reg,                     \
                     _shift, _width, _flags)                            \
        SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0,     \
                                _shift, _width, _flags, CLK_HW_INIT)

#define SPRD_DIV_CLK_FW_NAME(_struct, _name, _parent, _reg,             \
                        _shift, _width, _flags)                         \
        SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0,     \
                                _shift, _width, _flags, CLK_HW_INIT_FW_NAME)

#define SPRD_DIV_CLK_HW(_struct, _name, _parent, _reg,                  \
                        _shift, _width, _flags)                         \
        SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0,     \
                                _shift, _width, _flags, CLK_HW_INIT_HW)

static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw)
{
        struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);

        return container_of(common, struct sprd_div, common);
}

unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
                                          const struct sprd_div_internal *div,
                                          unsigned long parent_rate);

int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
                             const struct sprd_div_internal *div,
                             unsigned long rate,
                             unsigned long parent_rate);

extern const struct clk_ops sprd_div_ops;

#endif /* _SPRD_DIV_H_ */