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确认是否被配置成其他功能了。