cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-rk808.c (5137B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Clkout driver for Rockchip RK808
      4 *
      5 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
      6 *
      7 * Author:Chris Zhong <zyw@rock-chips.com>
      8 */
      9
     10#include <linux/clk-provider.h>
     11#include <linux/module.h>
     12#include <linux/slab.h>
     13#include <linux/platform_device.h>
     14#include <linux/mfd/rk808.h>
     15#include <linux/i2c.h>
     16
     17struct rk808_clkout {
     18	struct rk808 *rk808;
     19	struct clk_hw		clkout1_hw;
     20	struct clk_hw		clkout2_hw;
     21};
     22
     23static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw,
     24					      unsigned long parent_rate)
     25{
     26	return 32768;
     27}
     28
     29static int rk808_clkout2_enable(struct clk_hw *hw, bool enable)
     30{
     31	struct rk808_clkout *rk808_clkout = container_of(hw,
     32							 struct rk808_clkout,
     33							 clkout2_hw);
     34	struct rk808 *rk808 = rk808_clkout->rk808;
     35
     36	return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG,
     37				  CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
     38}
     39
     40static int rk808_clkout2_prepare(struct clk_hw *hw)
     41{
     42	return rk808_clkout2_enable(hw, true);
     43}
     44
     45static void rk808_clkout2_unprepare(struct clk_hw *hw)
     46{
     47	rk808_clkout2_enable(hw, false);
     48}
     49
     50static int rk808_clkout2_is_prepared(struct clk_hw *hw)
     51{
     52	struct rk808_clkout *rk808_clkout = container_of(hw,
     53							 struct rk808_clkout,
     54							 clkout2_hw);
     55	struct rk808 *rk808 = rk808_clkout->rk808;
     56	uint32_t val;
     57
     58	int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val);
     59
     60	if (ret < 0)
     61		return ret;
     62
     63	return (val & CLK32KOUT2_EN) ? 1 : 0;
     64}
     65
     66static const struct clk_ops rk808_clkout1_ops = {
     67	.recalc_rate = rk808_clkout_recalc_rate,
     68};
     69
     70static const struct clk_ops rk808_clkout2_ops = {
     71	.prepare = rk808_clkout2_prepare,
     72	.unprepare = rk808_clkout2_unprepare,
     73	.is_prepared = rk808_clkout2_is_prepared,
     74	.recalc_rate = rk808_clkout_recalc_rate,
     75};
     76
     77static struct clk_hw *
     78of_clk_rk808_get(struct of_phandle_args *clkspec, void *data)
     79{
     80	struct rk808_clkout *rk808_clkout = data;
     81	unsigned int idx = clkspec->args[0];
     82
     83	if (idx >= 2) {
     84		pr_err("%s: invalid index %u\n", __func__, idx);
     85		return ERR_PTR(-EINVAL);
     86	}
     87
     88	return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw;
     89}
     90
     91static int rk817_clkout2_enable(struct clk_hw *hw, bool enable)
     92{
     93	struct rk808_clkout *rk808_clkout = container_of(hw,
     94							 struct rk808_clkout,
     95							 clkout2_hw);
     96	struct rk808 *rk808 = rk808_clkout->rk808;
     97
     98	return regmap_update_bits(rk808->regmap, RK817_SYS_CFG(1),
     99				  RK817_CLK32KOUT2_EN,
    100				  enable ? RK817_CLK32KOUT2_EN : 0);
    101}
    102
    103static int rk817_clkout2_prepare(struct clk_hw *hw)
    104{
    105	return rk817_clkout2_enable(hw, true);
    106}
    107
    108static void rk817_clkout2_unprepare(struct clk_hw *hw)
    109{
    110	rk817_clkout2_enable(hw, false);
    111}
    112
    113static int rk817_clkout2_is_prepared(struct clk_hw *hw)
    114{
    115	struct rk808_clkout *rk808_clkout = container_of(hw,
    116							 struct rk808_clkout,
    117							 clkout2_hw);
    118	struct rk808 *rk808 = rk808_clkout->rk808;
    119	unsigned int val;
    120
    121	int ret = regmap_read(rk808->regmap, RK817_SYS_CFG(1), &val);
    122
    123	if (ret < 0)
    124		return 0;
    125
    126	return (val & RK817_CLK32KOUT2_EN) ? 1 : 0;
    127}
    128
    129static const struct clk_ops rk817_clkout2_ops = {
    130	.prepare = rk817_clkout2_prepare,
    131	.unprepare = rk817_clkout2_unprepare,
    132	.is_prepared = rk817_clkout2_is_prepared,
    133	.recalc_rate = rk808_clkout_recalc_rate,
    134};
    135
    136static const struct clk_ops *rkpmic_get_ops(long variant)
    137{
    138	switch (variant) {
    139	case RK809_ID:
    140	case RK817_ID:
    141		return &rk817_clkout2_ops;
    142	/*
    143	 * For the default case, it match the following PMIC type.
    144	 * RK805_ID
    145	 * RK808_ID
    146	 * RK818_ID
    147	 */
    148	default:
    149		return &rk808_clkout2_ops;
    150	}
    151}
    152
    153static int rk808_clkout_probe(struct platform_device *pdev)
    154{
    155	struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
    156	struct i2c_client *client = rk808->i2c;
    157	struct device_node *node = client->dev.of_node;
    158	struct clk_init_data init = {};
    159	struct rk808_clkout *rk808_clkout;
    160	int ret;
    161
    162	rk808_clkout = devm_kzalloc(&client->dev,
    163				    sizeof(*rk808_clkout), GFP_KERNEL);
    164	if (!rk808_clkout)
    165		return -ENOMEM;
    166
    167	rk808_clkout->rk808 = rk808;
    168
    169	init.parent_names = NULL;
    170	init.num_parents = 0;
    171	init.name = "rk808-clkout1";
    172	init.ops = &rk808_clkout1_ops;
    173	rk808_clkout->clkout1_hw.init = &init;
    174
    175	/* optional override of the clockname */
    176	of_property_read_string_index(node, "clock-output-names",
    177				      0, &init.name);
    178
    179	ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw);
    180	if (ret)
    181		return ret;
    182
    183	init.name = "rk808-clkout2";
    184	init.ops = rkpmic_get_ops(rk808->variant);
    185	rk808_clkout->clkout2_hw.init = &init;
    186
    187	/* optional override of the clockname */
    188	of_property_read_string_index(node, "clock-output-names",
    189				      1, &init.name);
    190
    191	ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw);
    192	if (ret)
    193		return ret;
    194
    195	return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_rk808_get,
    196					   rk808_clkout);
    197}
    198
    199static struct platform_driver rk808_clkout_driver = {
    200	.probe = rk808_clkout_probe,
    201	.driver		= {
    202		.name	= "rk808-clkout",
    203	},
    204};
    205
    206module_platform_driver(rk808_clkout_driver);
    207
    208MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs");
    209MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
    210MODULE_LICENSE("GPL");
    211MODULE_ALIAS("platform:rk808-clkout");