linux 电源管理子系统驱动范例
pm子系统控制器范例如下// SPDX-License-Identifier: GPL-2.0//#define DEBUG#includelinux/slab.h#includelinux/io.h#includelinux/spinlock.h#includelinux/pm_domain.h#includelinux/delay.h#includedt-bindings/clock/cru_temp_dts.h#includetemp_clk.h#defineSYS_PWR_CTL_OFF0x8#defineSYS_PWR_STATUS_OFF0xcstructpower_desc{constchar*constname;uint8_tbit;unsignedintflags;};structtemp_power_dev{structtemp_power*power;structgeneric_pm_domaingenpd;//表示需要初始化的电源域对象uint32_tmask;};structtemp_power{void__iomem*base;spinlock_tlock;structtemp_power_dev*dev;structgenpd_onecell_datagenpd_data;structgeneric_pm_domain**genpd;};#definePOWER_DESC_ITEM(NAME,BIT,FLAGS){\.name(NAME),\.bit(BIT),\.flags(FLAGS),\}staticstructpower_descpower_desc_table[]{POWER_DESC_ITEM(cpu0,PWR_CPU0,GENPD_FLAG_ALWAYS_ON),POWER_DESC_ITEM(cpu1,PWR_CPU1,GENPD_FLAG_ALWAYS_ON),POWER_DESC_ITEM(cpu2,PWR_CPU2,GENPD_FLAG_ALWAYS_ON),POWER_DESC_ITEM(cpu3,PWR_CPU3,GENPD_FLAG_ALWAYS_ON),POWER_DESC_ITEM(epp0,PWR_EPP0,0),POWER_DESC_ITEM(epp1,PWR_EPP1,0),POWER_DESC_ITEM(epp2,PWR_EPP2,0),POWER_DESC_ITEM(epp3,PWR_EPP3,0),POWER_DESC_ITEM(vpu0,PWR_VPU0,0),POWER_DESC_ITEM(vpu1,PWR_VPU1,0),POWER_DESC_ITEM(vpu2,PWR_VPU2,0),POWER_DESC_ITEM(npu,PWR_NPU,0),POWER_DESC_ITEM(pcie,PWR_PCIE,0),};staticinttemp_power_get_state(structtemp_power_dev*pmd,bool*is_on){structtemp_power*powerpmd-power;if(!pmd-mask){*is_onfalse;pr_err(%s: mask is a invalid parameter\n,__func__);return-EINVAL;}/* * System Power Status SYS_PWR_STATUS * 1: power on * 0: power off * */*is_onreadl(power-baseSYS_PWR_STATUS_OFF)pmd-mask;pr_debug(%s: [%-4s] get power is %d, val0x%08x, mask0x%08x\n,__func__,pmd-genpd.name,*is_on,readl(power-baseSYS_PWR_STATUS_OFF),pmd-mask);return0;}staticinttemp_power_set_state(structtemp_power_dev*pmd,bool on){structtemp_power*powerpmd-power;uint32_tval,retry0,max_retry20;bool status;if(!pmd-mask){pr_err(%s: mask is a invalid parameter\n,__func__);return-EINVAL;}/* * System Power Control SYS_PWR_CTRL * 1: power off; * 0: power on * */spin_lock(power-lock);valreadl(power-baseSYS_PWR_CTL_OFF);if(on)val~pmd-mask;elseval|pmd-mask;writel(val,power-baseSYS_PWR_CTL_OFF);do{statusreadl(power-baseSYS_PWR_STATUS_OFF)pmd-mask;udelay(1);retry;}while(on!statusretrymax_retry);pr_debug(%s: [%-4s] set power is %d, ctl val0x%x, status val0x%x, retry%d\n,__func__,pmd-genpd.name,on,readl(power-baseSYS_PWR_CTL_OFF),readl(power-baseSYS_PWR_STATUS_OFF),retry);spin_unlock(power-lock);if(retrymax_retry){pr_err(%s: [%s] set failed, on%d\n,__func__,pmd-genpd.name,on);return-1;}return0;}staticinttemp_power_on(structgeneric_pm_domain*genpd){structtemp_power_dev*pmdcontainer_of(genpd,structtemp_power_dev,genpd);returntemp_power_set_state(pmd,true);}staticinttemp_power_off(structgeneric_pm_domain*genpd){structtemp_power_dev*pmdcontainer_of(genpd,structtemp_power_dev,genpd);returntemp_power_set_state(pmd,false);}int__inittemp_register_power(structdevice_node*np,void__iomem*base){structtemp_power*power;structpower_desc*entry,*tablepower_desc_table;unsignedintidx0;intret;powerkzalloc(sizeof(*power),GFP_KERNEL);if(!power){pr_err(%s: failed to alloc power\n,__func__);return-ENOMEM;}power-basebase;spin_lock_init(power-lock);power-genpd_data.num_domainsPWR_MAX_NR;power-devkcalloc(power-genpd_data.num_domains,sizeof(structtemp_power_dev),GFP_KERNEL);if(!power-dev){pr_err(%s: failed to alloc power_dev.\n,__func__);return-ENOMEM;}power-genpdkcalloc(power-genpd_data.num_domains,sizeof(structgeneric_pm_domain*),GFP_KERNEL);if(!power-genpd){pr_err(%s: failed to alloc genpd.\n,__func__);return-ENOMEM;}power-genpd_data.domainspower-genpd;for(entrytable;entry-name;entry){structtemp_power_dev*pmdpower-dev[idx];bool is_on;pmd-powerpower;pmd-maskBIT(entry-bit);pmd-genpd.nameentry-name;pmd-genpd.flagsentry-flags;rettemp_power_get_state(pmd,is_on);if(ret)pr_warn(%s: unable to get current state for %s\n,__func__,pmd-genpd.name);//重点实现的两个函数pmd-genpd.power_ontemp_power_on;pmd-genpd.power_offtemp_power_off;/* 初始化一个通用I/O电源域对象 genpd: 指向需要初始化的PM域对象 gov: 与该域关联的 PM 域管理器可为 NULL is_off: 指定域的初始电源状态开或关 */retpm_genpd_init(pmd-genpd,NULL,!is_on);if(ret)pr_warn(%s: [%s] pm genpd init err. is_on%d, ret%d,__func__,pmd-genpd.name,is_on,ret);power-genpd[entry-bit]pmd-genpd;idx;}//完成power domain的注册retof_genpd_add_provider_onecell(np,power-genpd_data);if(ret){pr_err(%s: failed to register genpd driver: %d\n,__func__,ret);returnret;}pr_notice(%s: registered %u power domains\n,__func__,idx);return0;}在设备树里主要实现power-domains属性例如power-domainscru PWR_PCIE;参考http://www.wowotech.net/pm_subsystem/pm_architecture.html

相关新闻