119 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Clock driver for Hi655x4 *5 * Copyright (c) 2017, Linaro Ltd.6 *7 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>8 */9#include <linux/clk-provider.h>10#include <linux/module.h>11#include <linux/platform_device.h>12#include <linux/regmap.h>13#include <linux/slab.h>14#include <linux/mfd/core.h>15#include <linux/mfd/hi655x-pmic.h>16 17#define HI655X_CLK_BASE HI655X_BUS_ADDR(0x1c)18#define HI655X_CLK_SET BIT(6)19 20struct hi655x_clk {21 struct hi655x_pmic *hi655x;22 struct clk_hw clk_hw;23};24 25static unsigned long hi655x_clk_recalc_rate(struct clk_hw *hw,26 unsigned long parent_rate)27{28 return 32768;29}30 31static int hi655x_clk_enable(struct clk_hw *hw, bool enable)32{33 struct hi655x_clk *hi655x_clk =34 container_of(hw, struct hi655x_clk, clk_hw);35 36 struct hi655x_pmic *hi655x = hi655x_clk->hi655x;37 38 return regmap_update_bits(hi655x->regmap, HI655X_CLK_BASE,39 HI655X_CLK_SET, enable ? HI655X_CLK_SET : 0);40}41 42static int hi655x_clk_prepare(struct clk_hw *hw)43{44 return hi655x_clk_enable(hw, true);45}46 47static void hi655x_clk_unprepare(struct clk_hw *hw)48{49 hi655x_clk_enable(hw, false);50}51 52static int hi655x_clk_is_prepared(struct clk_hw *hw)53{54 struct hi655x_clk *hi655x_clk =55 container_of(hw, struct hi655x_clk, clk_hw);56 struct hi655x_pmic *hi655x = hi655x_clk->hi655x;57 int ret;58 uint32_t val;59 60 ret = regmap_read(hi655x->regmap, HI655X_CLK_BASE, &val);61 if (ret < 0)62 return ret;63 64 return val & HI655X_CLK_BASE;65}66 67static const struct clk_ops hi655x_clk_ops = {68 .prepare = hi655x_clk_prepare,69 .unprepare = hi655x_clk_unprepare,70 .is_prepared = hi655x_clk_is_prepared,71 .recalc_rate = hi655x_clk_recalc_rate,72};73 74static int hi655x_clk_probe(struct platform_device *pdev)75{76 struct device *parent = pdev->dev.parent;77 struct hi655x_pmic *hi655x = dev_get_drvdata(parent);78 struct hi655x_clk *hi655x_clk;79 const char *clk_name = "hi655x-clk";80 struct clk_init_data init = {81 .name = clk_name,82 .ops = &hi655x_clk_ops83 };84 int ret;85 86 hi655x_clk = devm_kzalloc(&pdev->dev, sizeof(*hi655x_clk), GFP_KERNEL);87 if (!hi655x_clk)88 return -ENOMEM;89 90 of_property_read_string_index(parent->of_node, "clock-output-names",91 0, &clk_name);92 93 hi655x_clk->clk_hw.init = &init;94 hi655x_clk->hi655x = hi655x;95 96 platform_set_drvdata(pdev, hi655x_clk);97 98 ret = devm_clk_hw_register(&pdev->dev, &hi655x_clk->clk_hw);99 if (ret)100 return ret;101 102 return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,103 &hi655x_clk->clk_hw);104}105 106static struct platform_driver hi655x_clk_driver = {107 .probe = hi655x_clk_probe,108 .driver = {109 .name = "hi655x-clk",110 },111};112 113module_platform_driver(hi655x_clk_driver);114 115MODULE_DESCRIPTION("Clk driver for the hi655x series PMICs");116MODULE_AUTHOR("Daniel Lezcano <daniel.lezcano@linaro.org>");117MODULE_LICENSE("GPL");118MODULE_ALIAS("platform:hi655x-clk");119