【平台信息】
平台:Rockchip
CPU:RK3288
PMU:RK808-B
开机流程:
1)当有接适配器时:VDC 电压升高; VSYS 上电; PMIC 上电并输出。
2)当只接电池时,按开机键:PWRON 拉高; PMIC 上电并输出。PMIC 启动,实现 EPROM 中的默认设置,各路上电完成后,发送 reset 信号,芯片上电,系统启动,PMIC 设备挂载,通过I2C 重新配置 PMIC。
【流程梳理】
1、设备树配置
kernel/arch/arm/boot/dts/rk808.dtsi
&rk808 {
compatible = "rockchip,rk808";
regulators {
#address-cells = <1>;
#size-cells = <0>;
rk808_dcdc1_reg: regulator@0 {
reg = <0>;
regulator-compatible = "rk_dcdc1";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1500000>;
regulator-initial-mode = <0x2>;
regulator-initial-state = <3>;
regulator-state-mem {
regulator-state-mode = <0x2>;
regulator-state-disabled;//disabled
regulator-state-uv = <900000>;
};
};
...
rk808_ldo1_reg: regulator@4 {
reg = <4>;
regulator-compatible = "rk_ldo1";
regulator-initial-state = <3>;
regulator-state-mem {
regulator-state-enabled;
regulator-state-uv = <3300000>;
};
};
...
kernel/arch/arm/boot/dts/rk3288-n1904.dts
&i2c0 {
status = "okay";
rk808: rk808@1b {
reg = <0x1b>;
status = "okay";
};
...
}
&rk808 {
gpios =<&gpio0 GPIO_A4 GPIO_ACTIVE_HIGH>,<&gpio0 GPIO_A0 GPIO_ACTIVE_HIGH>;
rk808,system-power-controller;
regulators {
rk808_dcdc1_reg: regulator@0{
regulator-name= "vdd_arm";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
};
...
rk808_ldo1_reg: regulator@4 {
regulator-name= "rk_ldo1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
...
};
};
参考文档:
Documentation/devicetree/bindings/mfd/rk808.txt
Documentation/devicetree/bindings/regulator/regulator.txt
2、驱动代码
kernel/drivers/mfd/rk808.c
static struct rk808_board *rk808_parse_dt(struct rk808 *rk808)
{
struct rk808_board *pdata;
struct device_node *regs,*rk808_pmic_np;
int i, count;
rk808_pmic_np = of_node_get(rk808->dev->of_node);
if (!rk808_pmic_np) {
printk("could not find pmic sub-noden");
return NULL;
}
regs = of_find_node_by_name(rk808_pmic_np, "regulators");
if (!regs)
return NULL;
count = of_regulator_match(rk808->dev, regs, rk808_reg_matches,
rk808_NUM_REGULATORS); // 匹配并查找设备树中regulator个数
of_node_put(regs);
if ((count < 0) || (count > rk808_NUM_REGULATORS))
return NULL;
pdata = devm_kzalloc(rk808->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
for (i = 0; i < count; i++) {
if (!rk808_reg_matches.init_data || !rk808_reg_matches.of_node)
continue;
pdata->rk808_init_data = rk808_reg_matches.init_data;
pdata->of_node = rk808_reg_matches.of_node;
}
pdata->irq = rk808->chip_irq;
pdata->irq_base = -1;
pdata->irq_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",0);
if (!gpio_is_valid(pdata->irq_gpio)) {
printk("invalid gpio: %dn", pdata->irq_gpio);
return NULL;
}
pdata->pmic_sleep_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",1);
if (!gpio_is_valid(pdata->pmic_sleep_gpio)) {
printk("invalid gpio: %dn", pdata->pmic_sleep_gpio);
}
pdata->pmic_sleep = true;
pdata->pm_off = of_property_read_bool(rk808_pmic_np,"rk808,system-power-controller");
return pdata;
}
static int rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
struct rk808 *rk808;
...
rk808 = devm_kzalloc(&i2c->dev,sizeof(struct rk808), GFP_KERNEL);
rk808->i2c = i2c;
rk808->dev = &i2c->dev;
i2c_set_clientdata(i2c, rk808);
...
ret = rk808_pre_init(rk808); //rk808工作状态初始化,配置一堆寄存器
if (rk808->dev->of_node)
pdev = rk808_parse_dt(rk808); //设备树解析
/******************************set sleep vol & dcdc mode******************/
#ifdef CONFIG_OF
rk808->pmic_sleep_gpio = pdev->pmic_sleep_gpio;
if (rk808->pmic_sleep_gpio) {
ret = gpio_request(rk808->pmic_sleep_gpio, "rk808_pmic_sleep");
if (ret < 0) {
dev_err(rk808->dev,"Failed to request gpio %d with ret:""%dn", rk808->pmic_sleep_gpio, ret);
return IRQ_NONE;
}
gpio_direction_output(rk808->pmic_sleep_gpio,0);
ret = gpio_get_value(rk808->pmic_sleep_gpio);
gpio_free(rk808->pmic_sleep_gpio);
pr_info("%s: rk808_pmic_sleep=%xn", __func__, ret);
}
#endif
if (pdev) {
rk808->num_regulators = rk808_NUM_REGULATORS;
rk808->rdev = kcalloc(rk808_NUM_REGULATORS,sizeof(struct regulator_dev *), GFP_KERNEL);
if (!rk808->rdev) {
return -ENOMEM;
}
/* Instantiate the regulators */
for (i = 0; i < rk808_NUM_REGULATORS; i++) {
reg_data = pdev->rk808_init_data;
if (!reg_data)
continue;
config.dev = rk808->dev;
config.driver_data = rk808;
config.regmap = rk808->regmap;
if (rk808->dev->of_node)
config.of_node = pdev->of_node;
if (reg_data && reg_data->constraints.name)
rail_name = reg_data->constraints.name;
else
rail_name = regulators.name;
reg_data->supply_regulator = rail_name;
config.init_data =reg_data;
rk808_rdev = regulator_register(®ulators,&config);
if (IS_ERR(rk808_rdev)) {
printk("failed to register %d regulatorn",i);
goto err;
}
rk808->rdev = rk808_rdev;
} // end for
} // end if
rk808->irq_gpio = pdev->irq_gpio;
ret = rk808_irq_init(rk808, rk808->irq_gpio, pdev);
if (ret < 0)
goto err;
ret = mfd_add_devices(rk808->dev, -1,
rk808s, ARRAY_SIZE(rk808s),
NULL, 0,NULL);
g_rk808 = rk808;
if (pdev->pm_off && !pm_power_off) {
pm_power_off = rk808_device_shutdown;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
rk808->rk808_suspend.suspend = rk808_early_suspend,
rk808->rk808_suspend.resume = rk808_late_resume,
rk808->rk808_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
register_early_suspend(&rk808->rk808_suspend);
#endif
rk808_kobj = kobject_create_and_add("rk808", NULL);
if (!rk808_kobj)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(rk808_attrs); i++) {
ret = sysfs_create_file(rk808_kobj, &rk808_attrs.attr);
if (ret != 0) {
printk("create index %d errorn", i);
return ret;
}
}
register_syscore_ops(&rk808_syscore_ops);
return 0;
}
static const struct i2c_device_id rk808_i2c_id[] = {
{ "rk808", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rk808_i2c_id);
static struct i2c_driver rk808_i2c_driver = {
.driver = {
.name = "rk808",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &rk808_pm_ops,
#endif
.of_match_table =of_match_ptr(rk808_of_match),
},
.probe = rk808_i2c_probe,
.remove = rk808_i2c_remove,
.id_table = rk808_i2c_id,
};
static int __init rk808_module_init(void)
{
int ret;
ret = i2c_add_driver(&rk808_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %dn", ret);
return ret;
}
subsys_initcall_sync(rk808_module_init);
【调试记录】
1、内核加载rk808驱动日志
rk808_i2c_probe,line=1355
rk808_pre_init,line=1224
of_get_named_gpio_flags exited with status 4
of_get_named_gpio_flags exited with status 0
vdd_arm: 712 <--> 1500 mV at 1312 mV
vdd_gpu: 712 <--> 1500 mV at 900 mV
rk_dcdc3: 1200 mV
vccio: 1800 <--> 3300 mV at 3300 mV
rk_ldo1: 1800 mV
rk_ldo2: 3300 mV
rk_ldo3: 1000 mV
rk_ldo4: 1800 mV
rk_ldo5: 3300 mV
rk_ldo6: 1800 mV
rk_ldo7: 1800 mV
rk_battery_charger_detect_cb , battery_charger_detect 1
rk_ldo8: 1800 mV
rk_ldo9: at 3300 mV
rk_ldo10: at 3300 mV
rk808_irq_init: rk808_pmic_irq=1
rk808_rtc_probe,line=540
rk808-rtc rk808-rtc: rtc core: registered rk808 as rtc0
rk808_rtc_probe:ok
【平台信息】
平台:Rockchip
CPU:RK3288
PMU:RK808-B
开机流程:
1)当有接适配器时:VDC 电压升高; VSYS 上电; PMIC 上电并输出。
2)当只接电池时,按开机键:PWRON 拉高; PMIC 上电并输出。PMIC 启动,实现 EPROM 中的默认设置,各路上电完成后,发送 reset 信号,芯片上电,系统启动,PMIC 设备挂载,通过I2C 重新配置 PMIC。
【流程梳理】
1、设备树配置
kernel/arch/arm/boot/dts/rk808.dtsi
&rk808 {
compatible = "rockchip,rk808";
regulators {
#address-cells = <1>;
#size-cells = <0>;
rk808_dcdc1_reg: regulator@0 {
reg = <0>;
regulator-compatible = "rk_dcdc1";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1500000>;
regulator-initial-mode = <0x2>;
regulator-initial-state = <3>;
regulator-state-mem {
regulator-state-mode = <0x2>;
regulator-state-disabled;//disabled
regulator-state-uv = <900000>;
};
};
...
rk808_ldo1_reg: regulator@4 {
reg = <4>;
regulator-compatible = "rk_ldo1";
regulator-initial-state = <3>;
regulator-state-mem {
regulator-state-enabled;
regulator-state-uv = <3300000>;
};
};
...
kernel/arch/arm/boot/dts/rk3288-n1904.dts
&i2c0 {
status = "okay";
rk808: rk808@1b {
reg = <0x1b>;
status = "okay";
};
...
}
&rk808 {
gpios =<&gpio0 GPIO_A4 GPIO_ACTIVE_HIGH>,<&gpio0 GPIO_A0 GPIO_ACTIVE_HIGH>;
rk808,system-power-controller;
regulators {
rk808_dcdc1_reg: regulator@0{
regulator-name= "vdd_arm";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
};
...
rk808_ldo1_reg: regulator@4 {
regulator-name= "rk_ldo1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
...
};
};
参考文档:
Documentation/devicetree/bindings/mfd/rk808.txt
Documentation/devicetree/bindings/regulator/regulator.txt
2、驱动代码
kernel/drivers/mfd/rk808.c
static struct rk808_board *rk808_parse_dt(struct rk808 *rk808)
{
struct rk808_board *pdata;
struct device_node *regs,*rk808_pmic_np;
int i, count;
rk808_pmic_np = of_node_get(rk808->dev->of_node);
if (!rk808_pmic_np) {
printk("could not find pmic sub-noden");
return NULL;
}
regs = of_find_node_by_name(rk808_pmic_np, "regulators");
if (!regs)
return NULL;
count = of_regulator_match(rk808->dev, regs, rk808_reg_matches,
rk808_NUM_REGULATORS); // 匹配并查找设备树中regulator个数
of_node_put(regs);
if ((count < 0) || (count > rk808_NUM_REGULATORS))
return NULL;
pdata = devm_kzalloc(rk808->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
for (i = 0; i < count; i++) {
if (!rk808_reg_matches.init_data || !rk808_reg_matches.of_node)
continue;
pdata->rk808_init_data = rk808_reg_matches.init_data;
pdata->of_node = rk808_reg_matches.of_node;
}
pdata->irq = rk808->chip_irq;
pdata->irq_base = -1;
pdata->irq_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",0);
if (!gpio_is_valid(pdata->irq_gpio)) {
printk("invalid gpio: %dn", pdata->irq_gpio);
return NULL;
}
pdata->pmic_sleep_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",1);
if (!gpio_is_valid(pdata->pmic_sleep_gpio)) {
printk("invalid gpio: %dn", pdata->pmic_sleep_gpio);
}
pdata->pmic_sleep = true;
pdata->pm_off = of_property_read_bool(rk808_pmic_np,"rk808,system-power-controller");
return pdata;
}
static int rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
struct rk808 *rk808;
...
rk808 = devm_kzalloc(&i2c->dev,sizeof(struct rk808), GFP_KERNEL);
rk808->i2c = i2c;
rk808->dev = &i2c->dev;
i2c_set_clientdata(i2c, rk808);
...
ret = rk808_pre_init(rk808); //rk808工作状态初始化,配置一堆寄存器
if (rk808->dev->of_node)
pdev = rk808_parse_dt(rk808); //设备树解析
/******************************set sleep vol & dcdc mode******************/
#ifdef CONFIG_OF
rk808->pmic_sleep_gpio = pdev->pmic_sleep_gpio;
if (rk808->pmic_sleep_gpio) {
ret = gpio_request(rk808->pmic_sleep_gpio, "rk808_pmic_sleep");
if (ret < 0) {
dev_err(rk808->dev,"Failed to request gpio %d with ret:""%dn", rk808->pmic_sleep_gpio, ret);
return IRQ_NONE;
}
gpio_direction_output(rk808->pmic_sleep_gpio,0);
ret = gpio_get_value(rk808->pmic_sleep_gpio);
gpio_free(rk808->pmic_sleep_gpio);
pr_info("%s: rk808_pmic_sleep=%xn", __func__, ret);
}
#endif
if (pdev) {
rk808->num_regulators = rk808_NUM_REGULATORS;
rk808->rdev = kcalloc(rk808_NUM_REGULATORS,sizeof(struct regulator_dev *), GFP_KERNEL);
if (!rk808->rdev) {
return -ENOMEM;
}
/* Instantiate the regulators */
for (i = 0; i < rk808_NUM_REGULATORS; i++) {
reg_data = pdev->rk808_init_data;
if (!reg_data)
continue;
config.dev = rk808->dev;
config.driver_data = rk808;
config.regmap = rk808->regmap;
if (rk808->dev->of_node)
config.of_node = pdev->of_node;
if (reg_data && reg_data->constraints.name)
rail_name = reg_data->constraints.name;
else
rail_name = regulators.name;
reg_data->supply_regulator = rail_name;
config.init_data =reg_data;
rk808_rdev = regulator_register(®ulators,&config);
if (IS_ERR(rk808_rdev)) {
printk("failed to register %d regulatorn",i);
goto err;
}
rk808->rdev = rk808_rdev;
} // end for
} // end if
rk808->irq_gpio = pdev->irq_gpio;
ret = rk808_irq_init(rk808, rk808->irq_gpio, pdev);
if (ret < 0)
goto err;
ret = mfd_add_devices(rk808->dev, -1,
rk808s, ARRAY_SIZE(rk808s),
NULL, 0,NULL);
g_rk808 = rk808;
if (pdev->pm_off && !pm_power_off) {
pm_power_off = rk808_device_shutdown;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
rk808->rk808_suspend.suspend = rk808_early_suspend,
rk808->rk808_suspend.resume = rk808_late_resume,
rk808->rk808_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
register_early_suspend(&rk808->rk808_suspend);
#endif
rk808_kobj = kobject_create_and_add("rk808", NULL);
if (!rk808_kobj)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(rk808_attrs); i++) {
ret = sysfs_create_file(rk808_kobj, &rk808_attrs.attr);
if (ret != 0) {
printk("create index %d errorn", i);
return ret;
}
}
register_syscore_ops(&rk808_syscore_ops);
return 0;
}
static const struct i2c_device_id rk808_i2c_id[] = {
{ "rk808", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rk808_i2c_id);
static struct i2c_driver rk808_i2c_driver = {
.driver = {
.name = "rk808",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &rk808_pm_ops,
#endif
.of_match_table =of_match_ptr(rk808_of_match),
},
.probe = rk808_i2c_probe,
.remove = rk808_i2c_remove,
.id_table = rk808_i2c_id,
};
static int __init rk808_module_init(void)
{
int ret;
ret = i2c_add_driver(&rk808_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %dn", ret);
return ret;
}
subsys_initcall_sync(rk808_module_init);
【调试记录】
1、内核加载rk808驱动日志
rk808_i2c_probe,line=1355
rk808_pre_init,line=1224
of_get_named_gpio_flags exited with status 4
of_get_named_gpio_flags exited with status 0
vdd_arm: 712 <--> 1500 mV at 1312 mV
vdd_gpu: 712 <--> 1500 mV at 900 mV
rk_dcdc3: 1200 mV
vccio: 1800 <--> 3300 mV at 3300 mV
rk_ldo1: 1800 mV
rk_ldo2: 3300 mV
rk_ldo3: 1000 mV
rk_ldo4: 1800 mV
rk_ldo5: 3300 mV
rk_ldo6: 1800 mV
rk_ldo7: 1800 mV
rk_battery_charger_detect_cb , battery_charger_detect 1
rk_ldo8: 1800 mV
rk_ldo9: at 3300 mV
rk_ldo10: at 3300 mV
rk808_irq_init: rk808_pmic_irq=1
rk808_rtc_probe,line=540
rk808-rtc rk808-rtc: rtc core: registered rk808 as rtc0
rk808_rtc_probe:ok
举报