summaryrefslogtreecommitdiff
path: root/drivers/clk/clk-rk808.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-rk808.c')
-rw-r--r--drivers/clk/clk-rk808.c100
1 files changed, 76 insertions, 24 deletions
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
index 8d90bdf5b946..f7412b137e5e 100644
--- a/drivers/clk/clk-rk808.c
+++ b/drivers/clk/clk-rk808.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Clkout driver for Rockchip RK808
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author:Chris Zhong <zyw@rock-chips.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
*/
#include <linux/clk-provider.h>
@@ -20,10 +12,9 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mfd/rk808.h>
-#include <linux/i2c.h>
struct rk808_clkout {
- struct rk808 *rk808;
+ struct regmap *regmap;
struct clk_hw clkout1_hw;
struct clk_hw clkout2_hw;
};
@@ -39,9 +30,8 @@ static int rk808_clkout2_enable(struct clk_hw *hw, bool enable)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
- struct rk808 *rk808 = rk808_clkout->rk808;
- return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG,
+ return regmap_update_bits(rk808_clkout->regmap, RK808_CLK32OUT_REG,
CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
}
@@ -60,10 +50,9 @@ static int rk808_clkout2_is_prepared(struct clk_hw *hw)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
- struct rk808 *rk808 = rk808_clkout->rk808;
uint32_t val;
- int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val);
+ int ret = regmap_read(rk808_clkout->regmap, RK808_CLK32OUT_REG, &val);
if (ret < 0)
return ret;
@@ -96,21 +85,84 @@ of_clk_rk808_get(struct of_phandle_args *clkspec, void *data)
return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw;
}
+static int rk817_clkout2_enable(struct clk_hw *hw, bool enable)
+{
+ struct rk808_clkout *rk808_clkout = container_of(hw,
+ struct rk808_clkout,
+ clkout2_hw);
+
+ return regmap_update_bits(rk808_clkout->regmap, RK817_SYS_CFG(1),
+ RK817_CLK32KOUT2_EN,
+ enable ? RK817_CLK32KOUT2_EN : 0);
+}
+
+static int rk817_clkout2_prepare(struct clk_hw *hw)
+{
+ return rk817_clkout2_enable(hw, true);
+}
+
+static void rk817_clkout2_unprepare(struct clk_hw *hw)
+{
+ rk817_clkout2_enable(hw, false);
+}
+
+static int rk817_clkout2_is_prepared(struct clk_hw *hw)
+{
+ struct rk808_clkout *rk808_clkout = container_of(hw,
+ struct rk808_clkout,
+ clkout2_hw);
+ unsigned int val;
+
+ int ret = regmap_read(rk808_clkout->regmap, RK817_SYS_CFG(1), &val);
+
+ if (ret < 0)
+ return 0;
+
+ return (val & RK817_CLK32KOUT2_EN) ? 1 : 0;
+}
+
+static const struct clk_ops rk817_clkout2_ops = {
+ .prepare = rk817_clkout2_prepare,
+ .unprepare = rk817_clkout2_unprepare,
+ .is_prepared = rk817_clkout2_is_prepared,
+ .recalc_rate = rk808_clkout_recalc_rate,
+};
+
+static const struct clk_ops *rkpmic_get_ops(long variant)
+{
+ switch (variant) {
+ case RK809_ID:
+ case RK817_ID:
+ return &rk817_clkout2_ops;
+ /*
+ * For the default case, it match the following PMIC type.
+ * RK805_ID
+ * RK808_ID
+ * RK818_ID
+ */
+ default:
+ return &rk808_clkout2_ops;
+ }
+}
+
static int rk808_clkout_probe(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
- struct i2c_client *client = rk808->i2c;
- struct device_node *node = client->dev.of_node;
+ struct device *dev = &pdev->dev;
struct clk_init_data init = {};
struct rk808_clkout *rk808_clkout;
int ret;
- rk808_clkout = devm_kzalloc(&client->dev,
+ dev->of_node = pdev->dev.parent->of_node;
+
+ rk808_clkout = devm_kzalloc(dev,
sizeof(*rk808_clkout), GFP_KERNEL);
if (!rk808_clkout)
return -ENOMEM;
- rk808_clkout->rk808 = rk808;
+ rk808_clkout->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!rk808_clkout->regmap)
+ return -ENODEV;
init.parent_names = NULL;
init.num_parents = 0;
@@ -119,22 +171,22 @@ static int rk808_clkout_probe(struct platform_device *pdev)
rk808_clkout->clkout1_hw.init = &init;
/* optional override of the clockname */
- of_property_read_string_index(node, "clock-output-names",
+ of_property_read_string_index(dev->of_node, "clock-output-names",
0, &init.name);
- ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw);
+ ret = devm_clk_hw_register(dev, &rk808_clkout->clkout1_hw);
if (ret)
return ret;
init.name = "rk808-clkout2";
- init.ops = &rk808_clkout2_ops;
+ init.ops = rkpmic_get_ops(rk808->variant);
rk808_clkout->clkout2_hw.init = &init;
/* optional override of the clockname */
- of_property_read_string_index(node, "clock-output-names",
+ of_property_read_string_index(dev->of_node, "clock-output-names",
1, &init.name);
- ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw);
+ ret = devm_clk_hw_register(dev, &rk808_clkout->clkout2_hw);
if (ret)
return ret;