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