SSD_PADMUX


1. Padmux是什么

Padmux是位于kernel\drivers\sstar\padmux的一个linux platform驱动。因为gpio pin复用的关系,通常同一个gpio可以用作不同的功能,所以我们就用padmux驱动在开机的时候统一将需要使用的gpio pin功能配置好。


2. PadMux驱动介绍

Padmux驱动定义如下:

2.  static struct platform_driver sstar_padmux_driver = {  
3.      .driver     = {  
4.          .name   = "padmux",  
5.          .owner  = THIS_MODULE,  
6.          .of_match_table = sstar_padmux_of_match,  
7.          .pm = &sstar_padmux_pm_ops,  
8.      },  
9.      .probe      = sstar_padmux_probe,  
10. };

需要关注的成员如下,下面会分别介绍。

sstar_padmux_of_match

sstar_padmux_pm_ops

sstar_padmux_probe


2.1. sstar_padmux_of_match

用来匹配开机需要配置的gpio table设备:

1.  static const struct of_device_id sstar_padmux_of_match[] = {  
2.      { .compatible = "sstar-padmux" },  
3.      { },  
4.  };

通过sstar-padmux在dts(例如:kernel\arch\arm\boot\dts pioneer3-ssc020a-s01a-demo-padmux.dtsi)中匹配到设备:

1.   padmux {  
2.      compatible = "sstar-padmux";  
3.      schematic =  
4.    
5.          //i2c1_mode_8, and set i2c-padmux = <8> int pioneer-demo.dtsi  
6.          <PAD_KEY8               PINMUX_FOR_I2C1_MODE_8       MDRV_PUSE_I2C1_SCL>,  
7.          <PAD_KEY9               PINMUX_FOR_I2C1_MODE_8       MDRV_PUSE_I2C1_SDA>,  
8.          <PAD_SR_IO16     PINMUX_FOR_GPIO_MODE         MDRV_PUSE_AIO_AMP_PWR >,  
9.    
10.         //SPI1 mode 6  
11.         <PAD_KEY10           PINMUX_FOR_SPI1_MODE_6       MDRV_PUSE_SPI1_CZ>,  
12.         <PAD_KEY11           PINMUX_FOR_SPI1_MODE_6       MDRV_PUSE_SPI1_CK>,  
13.         <PAD_KEY12           PINMUX_FOR_SPI1_MODE_6       MDRV_PUSE_SPI1_DI>,  
14.         <PAD_KEY13           PINMUX_FOR_SPI1_MODE_6       MDRV_PUSE_SPI1_DO>,  
15.   
16.         //pwm for backlight  
17.         <PAD_SR_IO08            PINMUX_FOR_PWM0_MODE_3       MDRV_PUSE_PWM0>,  
18.   
19.         <GPIO_NR                 PINMUX_FOR_UNKNOWN_MODE         MDRV_PUSE_NA>;  
20.   
21.     status = "ok"; // ok or disable  
22. };

2.2. sstar_padmux_pm_ops

实现str待机对应的resume和suspend函数:

1.  static const struct dev_pm_ops sstar_padmux_pm_ops = {  
2.      .suspend_late = sstar_padmux_suspend,  
3.      .resume_early  = sstar_padmux_resume,  
4.  };

2.3. sstar_padmux_probe

在匹配到padmux设备后,系统会call sstar_padmux_probe进行gpio功能配置:

1.  static int sstar_padmux_probe(struct platform_device *pdev)  
2.  {  
3.      _mdrv_padmux_dts(pdev->dev.of_node);  
4.      return 0;  
5.  }  
6.  static int _mdrv_padmux_dts(struct device_node* np)  
7.  {  
8.      int nPad;  
9.    
10.     if (0 >= (nPad = of_property_count_elems_of_size(np, PADINFO_NAME, sizeof(pad_info_t))))  
11.     {  
12.         PAD_PRINT("[%s][%d] invalid dts of padmux.schematic\n", __FUNCTION__, __LINE__);  
13.         return -1;  
14.     }  
15.     if (NULL == (_pPadInfo = kmalloc(nPad*sizeof(pad_info_t), GFP_KERNEL)))  
16.     {  
17.         PAD_PRINT("[%s][%d] kmalloc fail\n", __FUNCTION__, __LINE__);  
18.         return -1;  
19.     }  
20.     if (of_property_read_u32_array(np, PADINFO_NAME, (u32*)_pPadInfo, nPad*sizeof(pad_info_t)/sizeof(U32)))  
21.     {  
22.         PAD_PRINT("[%s][%d] of_property_read_u32_array fail\n", __FUNCTION__, __LINE__);  
23.         kfree(_pPadInfo);  
24.         _pPadInfo = NULL;  
25.         return -1;  
26.     }  
27.     _nPad = nPad;  
28.   
29.     {  
30.         int i;  
31.         PAD_PRINT("[%s][%d] *******************************\n", __FUNCTION__, __LINE__);  
32.         for (i = 0; i < _nPad; i++)  
33.         {  
34.             PAD_PRINT("[%s][%d] (PadId, Mode, Puse) = (%d, 0x%02x, 0x%08x)\n", __FUNCTION__, __LINE__,  
35.                 _pPadInfo[i].u32PadId,  
36.                 _pPadInfo[i].u32Mode,  
37.                 _pPadInfo[i].u32Puse);  
38.             MDrv_GPIO_PadVal_Set((U8)_pPadInfo[i].u32PadId & 0xFF, _pPadInfo[i].u32Mode);  
39.         }  
40.         PAD_PRINT("[%s][%d] *******************************\n", __FUNCTION__, __LINE__);  
41.     }  
42.   
43.     return 0;  
44. }

最终通过MDrv_GPIO_PadVal_Set将gpio配置成对应的功能:

kernel\drivers\sstar\gpio mdrv_gpio.c

1.  int MDrv_GPIO_PadVal_Set(U8 u8IndexGPIO, U32 u32PadMode)  
2.  {  
3.      return MHal_GPIO_PadVal_Set(u8IndexGPIO, u32PadMode);  
4.  }

kernel\drivers\sstar\gpio\pioneer3 mhal_gpio.c

1.  int MHal_GPIO_PadVal_Set(U8 u8IndexGPIO, U32 u32PadMode)  
2.  {  
3.      return HalPadSetVal((U32)u8IndexGPIO, u32PadMode);  
4.  }

kernel\drivers\sstar\gpio\pioneer3 mhal_pinmux.c

1.  S32 HalPadSetVal(U32 u32PadID, U32 u32Mode)  
2.  {  
3.      if (FALSE == _HalCheckPin(u32PadID)) {  
4.          return FALSE;  
5.      }  
6.      if(u32PadID>=PAD_ETH_RN && u32PadID <= PAD_SAR_GPIO3)  
7.          return HalPadSetMode_MISC(u32PadID, u32Mode);  
8.      return HalPadSetMode_General(u32PadID, u32Mode);  
9.  }  
10. static S32 HalPadSetMode_General(U32 u32PadID, U32 u32Mode)  
11. {  
12.     U32 u32RegAddr = 0;  
13.     U16 u16RegVal  = 0;  
14.     U8  u8ModeIsFind = 0;  
15.     U16 i = 0;  
16.   
17.     for (i = 0; i < sizeof(m_stPadMuxTbl)/sizeof(struct stPadMux); i++)  
18.     {  
19.         if (u32PadID == m_stPadMuxTbl[i].padID)  
20.         {  
21.             u32RegAddr = _RIUA_16BIT(m_stPadMuxTbl[i].base, m_stPadMuxTbl[i].offset);  
22.   
23.             if (u32Mode == m_stPadMuxTbl[i].mode)  
24.             {  
25.                 u16RegVal = _GPIO_R_WORD_MASK(u32RegAddr, 0xFFFF);  
26.                 u16RegVal &= ~(m_stPadMuxTbl[i].mask);  
27.                 u16RegVal |= m_stPadMuxTbl[i].val; // CHECK Multi-Pad Mode  
28.   
29.                 _GPIO_W_WORD_MASK(u32RegAddr, u16RegVal, 0xFFFF);  
30.   
31.                 u8ModeIsFind = 1;  
32. #if (ENABLE_CHECK_ALL_PAD_CONFLICT == 0)  
33.                 break;  
34. #endif  
35.             }  
36.             else  
37.             {   //Clear high priority setting  
38.                 u16RegVal = _GPIO_R_WORD_MASK(u32RegAddr, m_stPadMuxTbl[i].mask);  
39.                 if (u16RegVal == m_stPadMuxTbl[i].val)  
40.                 {  
41.                     printk(KERN_INFO"[Padmux]reset PAD%d(reg 0x%x:%x; mask0x%x) t0 %s (org: %s)\n",  
42.                            u32PadID,  
43.                            m_stPadMuxTbl[i].base,  
44.                            m_stPadMuxTbl[i].offset,  
45.                            m_stPadMuxTbl[i].mask,  
46.                            m_stPadModeInfoTbl[u32Mode].u8PadName,  
47.                            m_stPadModeInfoTbl[m_stPadMuxTbl[i].mode].u8PadName);  
48.                     if (m_stPadMuxTbl[i].val != 0)  
49.                     {  
50.                         _GPIO_W_WORD_MASK(u32RegAddr, 0, m_stPadMuxTbl[i].mask);  
51.                     }  
52.                     else  
53.                     {  
54.                         _GPIO_W_WORD_MASK(u32RegAddr, m_stPadMuxTbl[i].mask, m_stPadMuxTbl[i].mask);  
55.                     }  
56.                 }  
57.             }  
58.         }  
59.     }  
60.   
61.     return (u8ModeIsFind) ? 0 : -1;  
62. }

通过在m_stPadMuxTbl里面找到需要配置的gpio和mode设定对应的reg。

以PAD_TTL4配置成PINMUX_FOR_PWM0_MODE_4为例:

当在dts padmux里面配置了:

<PAD_TTL4      PINMUX_FOR_PWM0_MODE_4    MDRV_PUSE_PWM0>,

在probe的时候会根据m_stPadMuxTbl的寄存器设定将寄存器bank 0x103c offset 0x65的bit2设置为1:

1.  #define PADTOP_BANK                         0x103C00  
2.  #define REG_PWM0_MODE                           0x65  
3.  #define REG_PWM0_MODE_MASK                      BIT0|BIT1|BIT2|BIT3  
4.  {PAD_TTL4, PADTOP_BANK, REG_PWM0_MODE,  REG_PWM0_MODE_MASK,  BIT2, PINMUX_FOR_PWM0_MODE_4},

可以在板子通过读取reg确认设定有没有生效:


3. PadMux怎么用

通过上面padmux驱动的介绍,我们知道只要确认padmux驱动有enable,并在dts里面将需要配置的pin和对应的mode写进去,开机padmux probe的时候就会将gpio对应的功能配置好。需要注意的是pamdux驱动依赖gpio驱动,所以这两个驱动都要build进kernel。目前公板默认的配置gpio和padmux都有默认打开buildin:

1. CONFIG_MS_GPIO=y

2. CONFIG_MS_PADMUX=y

下面介绍如何在dts的padmux中配置对应的gpio功能。

3.1. 用哪个padmux dts文件

根据下面的follow由kernel config文件确定用哪个padmux dts文件。

kernel\arch\arm\configs\pioneer3_ssc020a_s01a_demo_defconfig:

1. CONFIG_SS_DTB_NAME="pioneer3-ssc020a-s01a-demo"

kernel\arch\arm\boot\dts\pioneer3-ssc020a-s01a-demo.dts:

1. #include "pioneer3.dtsi" 
2. #include "pioneer3-demo.dtsi" 
3. #include "pioneer3-ssc020a-s01a-demo-padmux.dtsi"

kernel\arch\arm\boot\dts\pioneer3-ssc020a-s01a-demo-padmux.dtsi


3.2. 配置gpio mode

根据SDK release的硬件发布资料SSDXXX HW CheckList V03.xlsx,找到padmux这栏:

以上图将PAD_TTL4配置成PWM0为例,可以看到PAD_TTL4要配置成PWM0只能将其配置成pwm0 mode 4,所以在padmux dts里面配置如下:

<PAD_TTL4      PINMUX_FOR_PWM0_MODE_4    MDRV_PUSE_PWM0>,

其中MDRV_PUSE_PWM0一般只做说明注释没有特殊用途,除非对应功能驱动有特别设定。其他i2c,spi,uart,ttl,mipi的设定也可以参考hw checklist在padmux dts配置。


4. 注意事项

同一个gpio pin只能复用成一种功能,不能同时在padmux配置成两种功能。如果在padmux配置的功能不生效,需要在dts确认是否被配置成其他功能了。