当前位置:网站首页>2022-08-02 Analyze RK817 output 32k clock PMIC_32KOUT_WIFI to WiFi module clock register devm_clk_hw_register
2022-08-02 Analyze RK817 output 32k clock PMIC_32KOUT_WIFI to WiFi module clock register devm_clk_hw_register
2022-08-04 08:33:00 【Haiyue Xichen】
一、RK817 输出32k clock PMIC_32KOUT_WIFI给WiFi模块,原理图如下


二、查看datasheet,控制这个clk输出在0xf2寄存器.

三、clk驱动在 kernel\drivers\clk\clk-rk808.c,其实就是通过i2c控制寄存器f2 enable 32k clk output.

/*
* Clkout driver for Rockchip RK808
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author:Chris Zhong <[email protected]>
*
* 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>
#include <linux/module.h>
#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 clk_hw clkout1_hw;
struct clk_hw clkout2_hw;
};
static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return 32768;
}
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,
CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
}
static int rk808_clkout2_prepare(struct clk_hw *hw)
{
return rk808_clkout2_enable(hw, true);
}
static void rk808_clkout2_unprepare(struct clk_hw *hw)
{
rk808_clkout2_enable(hw, false);
}
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);
if (ret < 0)
return ret;
return (val & CLK32KOUT2_EN) ? 1 : 0;
}
static const struct clk_ops rk808_clkout1_ops = {
.recalc_rate = rk808_clkout_recalc_rate,
};
static const struct clk_ops rk808_clkout2_ops = {
.prepare = rk808_clkout2_prepare,
.unprepare = rk808_clkout2_unprepare,
.is_prepared = rk808_clkout2_is_prepared,
.recalc_rate = rk808_clkout_recalc_rate,
};
static struct clk_hw *
of_clk_rk808_get(struct of_phandle_args *clkspec, void *data)
{
struct rk808_clkout *rk808_clkout = data;
unsigned int idx = clkspec->args[0];
if (idx >= 2) {
pr_err("%s: invalid index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
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);
struct rk808 *rk808 = rk808_clkout->rk808;
return regmap_update_bits(rk808->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);
struct rk808 *rk808 = rk808_clkout->rk808;
unsigned int val;
int ret = regmap_read(rk808->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 clk_init_data init = {};
struct rk808_clkout *rk808_clkout;
int ret;
rk808_clkout = devm_kzalloc(&client->dev,
sizeof(*rk808_clkout), GFP_KERNEL);
if (!rk808_clkout)
return -ENOMEM;
rk808_clkout->rk808 = rk808;
init.parent_names = NULL;
init.num_parents = 0;
init.name = "rk808-clkout1";
init.ops = &rk808_clkout1_ops;
rk808_clkout->clkout1_hw.init = &init;
/* optional override of the clockname */
of_property_read_string_index(node, "clock-output-names",
0, &init.name);
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw);
if (ret)
return ret;
init.name = "rk808-clkout2";
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",
1, &init.name);
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw);
if (ret)
return ret;
return of_clk_add_hw_provider(node, of_clk_rk808_get, rk808_clkout);
}
static int rk808_clkout_remove(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;
of_clk_del_provider(node);
return 0;
}
static struct platform_driver rk808_clkout_driver = {
.probe = rk808_clkout_probe,
.remove = rk808_clkout_remove,
.driver = {
.name = "rk808-clkout",
},
};
module_platform_driver(rk808_clkout_driver);
MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs");
MODULE_AUTHOR("Chris Zhong <[email protected]>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rk808-clkout");
四、用cat d/clk/clk_summary 命令查看是否注册成功

五、rk817中clock相关的dts配置

六、需要用到clk的WIFI驱动的dts的配置

七、获取clock并使能


八、使能该clk后,0xf2寄存器CLK32KOUT_EN会变1.

九、有价值的参考文章
边栏推荐
- 金仓数据库 KDTS 迁移工具使用指南 (6. 注意事项)
- 使用requests post请求爬取申万一级行业指数行情
- ShuffleNet v2网络结构复现(Pytorch版)
- 金仓数据库KingbaseES客户端编程接口指南-JDBC(10. JDBC 读写分离最佳实践)
- 智能健身动作识别:PP-TinyPose打造AI虚拟健身教练!
- 金仓数据库KingbaseES客户端编程接口指南-JDBC(5. JDBC 查询结果集处理)
- 研究性学习专题 3_LL(1)语法分析设计原理与实现
- [Computer recording screen] How to use bandicam to record the game setting graphic tutorial
- 力扣 剑指 Offer 04. 二维数组中的查找
- 金仓数据库 KDTS 迁移工具使用指南 (7. 部署常见问题)
猜你喜欢
随机推荐
【JS 逆向百例】某网站加速乐 Cookie 混淆逆向详解
C# 实用的第三方库
线程安全问题
Mysql insert on duplicate key 死锁问题定位与解决
form表单提交到数据库储存
解决循环依赖import cycle not allowed的最佳解决办法
智汇华云 | 华云软件定义网络 DCI介绍
js - the first letter that appears twice
关于常用状态码4XX提示错误
布局管理器
ShuffleNet v2网络结构复现(Pytorch版)
ShowMeAI —— Show u 三连
async - await
Recommend several methods that can directly translate PDF English documents
沃尔玛、阿里国际该如何做测评自养号?
The sorting algorithm including selection, bubble, and insertion
MYSQL JDBC图书管理系统
【虚幻引擎UE】UE5基于Gltf加载插件实现gltf格式骨骼动画在线/本地导入和切换
从底层看 Redis 的五种数据类型
安装GBase 8c数据库的时候,报错显示“Resource:gbase8c already in use”,这怎么处理呢?









