如何添加一个简单的文件节点提供给上层调用实例

前言:由于客户需要在系统里读到主板是否有出厂带电池,调过原理得知可以读取ADC通道值电压去检测是否带有电池,且电压值具体为多少,封装成设备节点然后供上层调用,写入app显示。(读取通道值有一个gpio使能口直连cpu,io拉高才能正确读取到准确电压,读完后需要拉低,仿照待机功耗增加)
在Kernel层driver/misc/mediatek/目录下新建一层目录mid_adc即可开始:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include

#define MID_ADC_DEVICE “mid_adc”
#define AUXADC_RTC_VOL_CHANNEL 2//channel 2 to read ADC voltage

//static DEFINE_MUTEX(mid_adc_set_gpio_mutex);

static struct pinctrl *pinctrl1;
static struct pinctrl_state *mid_adc_en_output_high,*mid_adc_en_output_low;
static DEFINE_MUTEX(mid_adc_ctrl_mutex);

static unsigned int rtc_adc_value = 0;

extern int IMM_IsAdcInitReady(void);
extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata);

static unsigned int rtc_get_current_voltage(int Channel)
{
int ret = 0, data[4], i, ret_value = 0, ret_temp = 0, times = 5;

   if (IMM_IsAdcInitReady() == 0) {
           printk( "[kzhkzh] AUXADC is not ready");
           return 0;
   }

   i = times;
   while (i--) {
           ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp);
		   printk("adc voltage[kzhkzh]ret_temp:%d\n",ret_temp);
           if (ret_value == 0) {
                   ret += ret_temp;
           } else {
                   times = times > 1 ? times - 1 : 1;
                   printk( "kzhkzh [rtc_get_current_voltage] ret_value=%d, times=%d\n",
                   ret_value, times);
           }
   }

   ret = ret*1500/4096;
   ret = ret/times;
   ret +=ret;//读取分压电压值x2

   return  ret;

}

int mid_adc_get_gpio_info(struct platform_device *pdev)
{
int ret;
printk("[kzhkzh] mid_adc_get_gpio_info start+++++++++++++++++\n");
pinctrl1 = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(pinctrl1)) {
ret = PTR_ERR(pinctrl1);
dev_err(&pdev->dev, “Cannot find mid_leds pinctrl1!\n”);
return ret;
}

mid_adc_en_output_high = pinctrl_lookup_state(pinctrl1, "mid_adc_en_output_high");
if (IS_ERR(mid_adc_en_output_high)) {
	ret = PTR_ERR(mid_adc_en_output_high);
	dev_err(&pdev->dev, "Cannot find mid_adc pinctrl mid_adc_en_output_high!\n");
	return ret;
}
mid_adc_en_output_low = pinctrl_lookup_state(pinctrl1, "mid_adc_en_output_low");
if (IS_ERR(mid_adc_en_output_low)) {
	ret = PTR_ERR(mid_adc_en_output_low);
	dev_err(&pdev->dev, "Cannot find mid_adc pinctrl mid_adc_en_output_low!\n");
	return ret;
}

printk("[kzhkzh] mid_adc_get_gpio_info end+++++++++++++++++\n");
return 0;

}

void mid_adc_en(int en)
{
if (en) {
pinctrl_select_state(pinctrl1, mid_adc_en_output_high);
printk("[kzhkzh] %s:%d set mid_adc_en_output_high 1\n",func,LINE);
} else {
pinctrl_select_state(pinctrl1, mid_adc_en_output_low);
printk("[kzhkzh] %s:%d set mid_adc_en_output_low 0\n",func,LINE);
}
}

//---------------------------------------------------------------------
// node1:sys/devices/platform/mid_adc/rtc_adc_status read rtc_vbat adc voltage value
// node2:sys/devices/platform/mid_adc/rtc_adc_en enable rtc_en pinctrl output high level or low level
static ssize_t show_mid_adc_read(struct device *dev,struct device_attribute *attr, char *buf)
{
printk(“show_mid_adc_read!!\n”);
return sprintf(buf, “%d\n”, rtc_get_current_voltage(AUXADC_RTC_VOL_CHANNEL));//kzhkzh 读取rtc adc 电压值到文件节点
}

static ssize_t mid_adc_en_store_ctrl(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
mutex_lock(&mid_adc_ctrl_mutex);

if (!strncmp(buf, "1", 1)) {//buf ==1
   printk("[kzhkzh] open mid_rtc_adc_en !!\n");
   mid_adc_en(1);
}else {
   printk("[kzhkzh] close mid_rtc_adc_en !!\n");
   mid_adc_en(0);
}
mutex_unlock(&mid_adc_ctrl_mutex);
return count;

}

static DEVICE_ATTR(rtc_adc_status, 0444, show_mid_adc_read,NULL);
static DEVICE_ATTR(rtc_adc_en, 0664, NULL,mid_adc_en_store_ctrl);
static struct attribute *mid_adc_attrs[] = {
&dev_attr_rtc_adc_en.attr,
&dev_attr_rtc_adc_status.attr,
NULL
};
static const struct attribute_group mid_adc_attrs_group = {
.attrs = mid_adc_attrs
};
//--------------------------------------------------------------------------

static int mid_adc_probe(struct platform_device *pdev)
{
int ret;

ret = mid_adc_get_gpio_info(pdev);
printk("kzhkzh %s:%d \n",__func__,__LINE__);
if (ret)
{
	pr_err("mid_adc_get_gpio_info failed!");
	return ret;
}
mid_adc_en(0);
rtc_adc_value = rtc_get_current_voltage(AUXADC_RTC_VOL_CHANNEL);
printk("[kzhkzh] %s:%d  rtc_adc_value:%d\n",__func__,__LINE__,rtc_adc_value);
//--------------------------------------------------------------------
ret = sysfs_create_group(&pdev->dev.kobj,&mid_adc_attrs_group);
printk("[kzhkzh] %s:%d ret:%d\n",__func__,__LINE__,ret);
if (ret < 0) {
	printk("[kzhkzh] %s: unable to create mid_adc_attrs_group\n", __func__);
}

//--------------------------------------------------------------------
printk(“[kzhkzh] %s:%d end\n”,func,LINE);
return 0;
}

static const struct of_device_id adc_match_table[] = {
{ .compatible = “mediatek,mid_adc”, },
{}
};

//MODULE_DEVICE_TABLE(of, adc_match_table);

static struct platform_driver mid_adc_driver = {
.probe = mid_adc_probe,
.driver = {
.name = MID_ADC_DEVICE,
.owner = THIS_MODULE,
.of_match_table = adc_match_table,
}
};

static int __init mid_adc_init(void)
{
int ret = 0;

ret = platform_driver_register(&mid_adc_driver);
printk("[kzhkzh] mid_adc_init  ret:%d !!!! \n");	
if (ret < 0)
	pr_err("unable to register mid_leds driver.\n");

return 0;

}

static void __exit mid_adc_exit(void)
{
platform_driver_unregister(&mid_adc_driver);
}

module_init(mid_adc_init);
module_exit(mid_adc_exit);

MODULE_LICENSE(“GPL”);
MODULE_DESCRIPTION(“MediaTek mid_adc_detect driver”);
MODULE_AUTHOR(“[email protected]”);

同时:dts增加节点

  •   mid_adc: mid_adc {
    
  •           compatible = "mediatek,mid_adc";
    
  •   };
    

+&mid_adc {

  •   //compatible = "mediatek,mid_adc";
    
  •   pinctrl-names = "mid_adc_default",
    
  •                   "mid_adc_en_output_high",
    
  •           "mid_adc_en_output_low";
    
  •   pinctrl-0 = <&mid_adc_default>;
    
  •   pinctrl-1 = <&mid_adc_en_output_high>;
    
  •   pinctrl-2 = <&mid_adc_en_output_low>;
    

+};
+&pio {

  •   mid_adc_default: mid_adc_default {
    
  •   };
    
  •   mid_adc_en_output_high: mid_adc_en_output_high {
    
  •           pins_cmd_dat {
    
  •                   pins = ;
    
  •                   slew-rate = <1>;
    
  •                   output-high;
    
  •           };
    
  •   };
    
  •   mid_adc_en_output_low: mid_adc_en_output_low {
    
  •           pins_cmd_dat {
    
  •                   pins = ;
    
  •                   slew-rate = <1>;
    
  •                   output-low;
    
  •           };
    
  •   };
    

最终节点注册挂载在:
// node1:sys/devices/platform/mid_adc/rtc_adc_status read rtc_vbat adc voltage value
// node2:sys/devices/platform/mid_adc/rtc_adc_en enable rtc_en pinctrl output high level or low level

你可能感兴趣的:(如何添加一个简单的文件节点提供给上层调用实例)