基于PM8916 MPP创建一个Linux led子系统

基于PM8916 MPP创建一个Linuxled子系统
首先,从kernel文件系统层面上创建sys文件系统节点/sys/class/leds/button-backlight/brightness的方法,是基于kernel部分驱动kernel/drivers/leds/leds-gpio.c创建的,其中dts中每一个子节点都对应一个Gpio的led,都会生成一个以label名称为目录的led类。
Dts配置如下:

&soc {
         gpio-leds {
                   compatible = "gpio-leds";
                   status = "okay";
                   pinctrl-names = "default";
                   pinctrl-0 = <&button_backlight_off>;
/*add by eliot shao add adevice led-breath at /sys/class/leds/led-breath- 2016/8/18*/
                   led-breath {
                            gpios =<&msm_gpio 8 0>; 
                            label = "led-breath-";
                            linux,default-trigger = "none";
                            default-state = "keep";   /*gpio value will keep prrvious value*/
                   };
                   keypad-backlight {
                            gpios =<&msm_gpio 119 0>;
                            label = "button-backlight";
                            linux,default-trigger = "none";
                   };
         };
};

但是如果控制引脚不是AP的gpio,而是PMIC上的MPP引脚,过程就不是这样的了。
PMIC上的MPP是多功能引脚的意思,可以做电源、gpio、ADC、PWM、SINK等功能。
在这里插入图片描述
2、 驱动程序
kernel/drivers/leds/leds-qpnp.c
这里说一下第一次遇到这种问题解决思路:
Mpp2脚控制LED,如果自己写驱动的话关键点是如何配置PM8916上和MPP上相关的寄存器,将MPP2配置成为GPIO或者pwm模式。写一个设置mpp2输出高低或者pwm频率的函数,包装成led的class注册到sys文件系统中。
找到PM 8916相关的dts文件,查看其支持的设备有哪些,查找和led相关的设备。
打开Y:\LA.BR.1.2.4-05310-8x16.0\kernel\arch\arm\boot\dts\qcom\msm-pm8916.dtsi
在&spmi_bus {};设备节点下定义了

qcom,pm8916@0 {
……
pm8916_leds: qcom,leds@a100 {
                         compatible= "qcom,leds-qpnp";
                         reg= <0xa100 0x100>;
                         label= "mpp";
               };
          };

继续跟踪compatible = “qcom,leds-qpnp”;检索qcom,leds-qpnp。
找到驱动文件:
kernel/drivers/leds/leds-qpnp.c
分析驱动:


#ifdefCONFIG_OF
staticstruct of_device_id spmi_match_table[] = {
  { .compatible = "qcom,leds-qpnp",},
  { },
};
#else
#definespmi_match_table NULL
#endif
 
staticstruct spmi_driver qpnp_leds_driver = {
  .driver       ={
       .name    ="qcom,leds-qpnp",
       .of_match_table = spmi_match_table,
  },
  .probe        =qpnp_leds_probe,
  .remove       =qpnp_leds_remove,
  };

在probe函数主要做一下事情:

1、解析dts各项,分配到structled_classdev cdev;
2、
led->cdev.brightness_set = qpnp_led_set;
led->cdev.brightness_get = qpnp_led_get;
qpnp_led_set函数调用__qpnp_led_work
–>
caseQPNP_ID_LED_MPP:
rc = qpnp_mpp_set(led);
–>
qpnp_led_masked_write(structqpnp_led_data *led, u16 addr, u8 mask, u8 val)
–>
spmi_ext_register_readl; spmi_ext_register_writel;读写PMICmpp相关寄存器。
–>
spmi_read_cmd(ctrl,SPMI_CMD_EXT_READL, sid, addr, len - 1, buf);
spmi_write_cmd(ctrl,op, sid, addr, len - 1, buf);
–>
pa_read_data; pmic_arb_write
–>
writel_relaxed(val,dev->wrbase + offset);
u32val = readl_relaxed(dev->rdbase + offset);
3、注册led_classdev_register(&spmi->dev,&led->cdev);
整个过程就是MPP+led子系统的架构,和GPIO+led子系统的架构类似,区别就是硬件控制方式。

3、 dts配置

&spmi_bus{
  qcom,pm8916@0 {
       qcom,leds@a100 {
           status = "okay";
           qcom,led_mpp_2 {
                label = "mpp";
                linux,name = "button-backlight";
                linux,default-trigger ="none";
                qcom,default-state ="off";
                qcom,max-current = <40>;
                qcom,current-setting =<5>;
                qcom,id = <6>;
                qcom,mode = "manual";
                qcom,source-sel = <1>;
                qcom,mode-ctrl =<0x10>;  /*change mode to digitaloutput*/
           };
       };
  };
 };

创建/sys/class/leds/button-backlight/brightness

发布了93 篇原创文章 · 获赞 10 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/jinron10/article/details/104667757