Analysis of LED Driver of Marvell (Marvell PXA310 LED驱动代码分析)

来源:互联网 发布:360浏览器 for mac 编辑:程序博客网 时间:2024/06/08 01:32

1.              Abstract

抱歉这篇报告是我当初用英文写的,有兴趣的朋友可以参考。

2.              Introduction

.

3.              Driver Codes

Codes exist indrivers/misc/misc_control.c.

3.1       Data Structure

The devicestructure in

3.2       InitializeCodes

3.2.1         Probe Function

Codes exist in drivers/misc/misc_control.c.

static int mctl_probe(struct platform_device *pdev)

{

       struct resource *res;

       int ret;

       mctl_hardware_init();

       res = platform_get_resource(pdev,IORESOURCE_MEM, 0); //This line is no sense since wehave not registered any IO resources.

       ret = misc_register(&misc_control_dev);

       ……

       return 0;

}

 

static int mctl_hardware_init(void)

{

       pxa3xx_mfp_set_configs(misc_ctl_pins, ARRAY_SIZE(misc_ctl_pins));//Please refer to section 3.4.1 and 3.4.2

       pxa3xx_gpio_set_direction(WIFI_LED_GPIO,GPIO_DIR_OUT);

       pxa3xx_gpio_set_level(WIFI_LED_GPIO,0);

       pxa3xx_gpio_set_direction(BT_LED_GPIO,GPIO_DIR_OUT);

       pxa3xx_gpio_set_level(BT_LED_GPIO,0);

       pxa3xx_gpio_set_direction(POWER_RED_LED_GPIO,GPIO_DIR_OUT);

       pxa3xx_gpio_set_level(POWER_RED_LED_GPIO,0);

       pxa3xx_gpio_set_direction(POWER_GREEN_LED_GPIO,GPIO_DIR_OUT);

       pxa3xx_gpio_set_level(POWER_GREEN_LED_GPIO,0);

       pxa3xx_gpio_set_direction(POWER_BLUE_LED_GPIO,GPIO_DIR_OUT);

       pxa3xx_gpio_set_level(POWER_BLUE_LED_GPIO,0);

       // Do reset for bluetoothchip

       mctl_bt_do_reset(); //It seemed that GPIO BT_RESET_GPIO is used to reset BTmodule

       return 0;

}

3.3       DriverOperation Codes

The following data structure is initialized in misc_register.

static const struct file_operations mctl_fops = {

      owner:THIS_MODULE,

      open:mctl_open,

      release:mctl_release,

      read:mctl_read,

      write:mctl_write,

      fasync:NULL,

      poll:NULL,

      ioctl:mctl_ioctl,

      llseek:no_llseek,

};

All functions except mctl_ioctl are empty.

static int mctl_ioctl(struct inode *inode, struct file *file, unsignedint cmd,

        unsigned long arg)

{

       int ret;

       void __user *argp = (void__user *)arg;

       struct misc_ctl_structm_ctl;

       switch (cmd) {

       case MCTL_GET_CTL:

              if(copy_from_user(&m_ctl, argp, sizeof(m_ctl)))

                     return-EFAULT;

              ret = do_mctl_get(&m_ctl); //Fetch the currentvalue, all of them are the current settings of GPIO

              if (ret)

                     return ret;

              returncopy_to_user(argp, &m_ctl, sizeof(m_ctl));

              break;

       case MCTL_SET_CTL:

              if(copy_from_user(&m_ctl, argp, sizeof(m_ctl)))

                     return-EFAULT;

              ret = do_mctl_set(&m_ctl); //Set the value of theLED, which will be explained later.

              if (ret)

                     return ret;

              return 0;

              break;

       default:

              return -EINVAL;

       }

       return 0;

}

 

static int do_mctl_set(struct misc_ctl_struct *m_ctl)

{

       switch(m_ctl->ctrl){

              caseCTRL_POWER_RED_LED:

                     pxa3xx_gpio_set_level(POWER_RED_LED_GPIO,!!m_ctl->val);

                     break;

              caseCTRL_POWER_GREEN_LED:

                     mctl_set_power_led_mode(m_ctl->val); //We will explain it later.

                     break;

              caseCTRL_POWER_BLUE_LED:

                     pxa3xx_gpio_set_level(POWER_BLUE_LED_GPIO,!!m_ctl->val);

                     break;

              case CTRL_WIFI_LED:

                     pxa3xx_gpio_set_level(WIFI_LED_GPIO,!!m_ctl->val);

                     break;

              case CTRL_BT_LED:

                     pxa3xx_gpio_set_level(BT_LED_GPIO,!!m_ctl->val);

                     break;

              case CTRL_BT_RESET:

                     if (m_ctl->val != 0)

                            mctl_bt_do_reset();

                     break;

              ……

       }

       return 0;

}

 

int mctl_set_power_led_mode(int setting)

{

       power_led_flip_mode = (setting & POWER_LED_MODE_MASK); //Get the flip mode

       //From now we compute the flip interval,or set it to 0 if no flip need.

       if  (power_led_flip_mode & (POWER_LED_MODE_NORMAL | POWER_LED_MODE_SLEEP ) ) {

              power_led_flip_interval= ( setting & POWER_LED_VALUE_MASK );

              if(!power_led_flip_interval)

                     power_led_flip_interval= 2;   // set default filping interval to2 seconds.

       }else{

              power_led_flip_interval= 0;

       }

       if  (power_led_flip_mode& POWER_LED_MODE_NORMAL) { //This is very strange,since we should also enable flip mode in POWER_LED_MODE_SLEEP

              mctl_enable_power_led_flip_hardware(); //Please refer to section 3.5

              return 0;

       }

       mctl_disable_power_led_flip_hardware(); //Disable flip now.

       // as long as GPIO mode isset and normal mode is not set. we control led with 0/1 through GPIO in fullpower state

       if  (power_led_flip_mode &POWER_LED_MODE_GPIO ) {

              pxa3xx_gpio_set_level(POWER_GREEN_LED_GPIO,!!( setting & POWER_LED_VALUE_MASK ));

              return 0;

       }

 

       // if only flip during sleepmode is set, we disable led in full power state.

       if  (power_led_flip_mode &POWER_LED_MODE_SLEEP) { //Close the LED during Sleepmode.

              pxa3xx_gpio_set_level(POWER_GREEN_LED_GPIO,0);

              return 0;

       }

       return -EINVAL;

}

3.4       The PinDescriptions

3.4.1         Function pxa3xx_mfp_set_config

First of all, let us see the data structure of pxa3xx_pin_config:

struct pxa3xx_pin_config {

       unsigned int mfp_pin; //The Pin register

       unsignedint reserved:16;

       unsigned int af_sel:3; //select the function of this pin

       unsigned int edge_rise_en:1; //enable rise edge detection.

       unsigned int edge_fall_en:1; //enable fall edge detection.

       unsigned int edge_clear:1; //enable edge detection.

       unsigned int sleep_oe_n:1; //determine the direction of this pin in low power mode.

       unsigned int sleep_data:1; //the output data in low power mode.

       unsigned int sleep_sel:1; //enable low power mode output.

       unsigned int drive:3; //Drive strength and slew rate

       unsigned int pulldown_en:1; //enable pull down function

       unsigned int pullup_en:1; //enable pull up function

       unsigned int pull_sel:1; //enable pull function

};

Please refer to document [1] P129 Section 4.11 forconcrete meaning of these fields.

#define PIN2REG(pin_config)                                  /

              (pin_config->af_sel<< MFPR_ALT_OFFSET) |     /

               (pin_config->edge_rise_en << MFPR_ERE_OFFSET ) |/

               (pin_config->edge_fall_en << MFPR_EFE_OFFSET ) |/

               (pin_config->edge_clear << MFPR_EC_OFFSET ) |   /

               (pin_config->sleep_oe_n << MFPR_SON_OFFSET ) |      /

               (pin_config->sleep_data << MFPR_SD_OFFSET ) |   /

               (pin_config->sleep_sel << MFPR_SS_OFFSET ) |       /

               (pin_config->drive << MFPR_DRV_OFFSET ) | /

               (pin_config->pulldown_en << MFPR_PD_OFFSET ) |      /

               (pin_config->pullup_en << MFPR_PU_OFFSET ) |    /

               (pin_config->pull_sel << MFPR_PS_OFFSET );

And now you should understand the meaning of functionpxa3xx_mfp_set_config.

3.4.2         Data Structure misc_ctl_pins

struct pxa3xx_pin_config misc_ctl_pins[] = {

PXA3xx_MFP_CFG("Wifi_LED",             WIFI_LED_GPIO, MFP_AF0, MFP_DS01X, 0, MFP_LPM_PULL_LOW, MFP_EDGE_NONE),

PXA3xx_MFP_CFG("Bluetooth _LED",    BT_LED_GPIO,      MFP_AF0,MFP_DS01X, 0, MFP_LPM_PULL_LOW, MFP_EDGE_NONE),

PXA3xx_MFP_CFG("POWER_RED_LED",   POWER_RED_LED_GPIO,        MFP_AF0,MFP_DS01X, 0, MFP_LPM_PULL_LOW, MFP_EDGE_NONE),

PXA3xx_MFP_CFG("POWER_GREEN_LED",     POWER_GREEN_LED_GPIO,         MFP_AF0,MFP_DS01X, 0, MFP_LPM_PULL_LOW, MFP_EDGE_NONE),

PXA3xx_MFP_CFG("POWER_BLUE_LED", POWER_BLUE_LED_GPIO,            MFP_AF0,MFP_DS01X, 0, MFP_LPM_PULL_LOW, MFP_EDGE_NONE),

PXA3xx_MFP_CFG("BT_RESET",           BT_RESET_GPIO, MFP_AF0, MFP_DS01X, 0, MFP_LPM_PULL_HIGH,MFP_EDGE_NONE),

};

 

#define PXA3xx_MFP_CFG(desc, pin, af, drv, rdh, lpm, edge) /

{                                               /

       .mfp_pin = pin,                               /

       .af_sel    = af,                                 /

       .reserved       = 0,                      /

       .drive            = drv,                         /

       .sleep_sel      = rdh,                         /

       .sleep_oe_n  = ((lpm) & 0x1),         /

       .sleep_data   = (((lpm) & 0x2)  >>1),          /

       .pullup_en    = (((lpm) & 0x4)  >>2),          /

       .pulldown_en      = (((lpm) & 0x8)  >>3),          /

       .pull_sel = (((lpm) & 0x10) >>4),           /

       .edge_clear   = (!(edge)),                 /

       .edge_fall_en      = ((edge) & 0x1),              /

       .edge_rise_en      = (((edge) & 0x2) >>1),           /

}

3.4.3         Function pxa3xx_mfp_set_afds

static voidmctl_disable_power_led_flip_hardware(void)

{

       OMCR10 = 0;

       // set pin back to GPIO

       pxa3xx_mfp_set_afds(POWER_GREEN_LED_GPIO, MFP_AF0, MFP_DS01X);//Please refer to following, When it is not used,reset the multi-function PIN of GPIO19 to 0, which is the primary function ofit: GPIO_19. See the explanation in Section 3.5

}

 

intpxa3xx_mfp_set_afds(unsigned int pin, int af, int ds)

{

       //dsis driver strength, in our case it is always 0. Please refer to document [1]P130 for details.

       uint32_t mfp_reg;

       unsigned long flags;

#if defined(CONFIG_PXA3xx_GPIOEX)

       if (IS_GPIO_EXP_PIN(pin))

              return 0;

#endif

       spin_lock_irqsave(&mfp_spin_lock,flags);

       mfp_reg = MFP_REG(pin); //Get the PIN Address, which isstarted from 0x40E1_0000

       mfp_reg &= ~(MFP_AF_MASK | MFP_DRV_MASK); //Clear AF and DRV fields

       mfp_reg |= (((af & 0x7) << MFPR_ALT_OFFSET) |

                  ((ds &0x7) << MFPR_DRV_OFFSET)); //Then set AF and DRVfields, AF is the function fields, and DRV is the driver strength fields

       MFP_REG(pin) = mfp_reg;

       mfp_reg = MFP_REG(pin);

       spin_unlock_irqrestore(&mfp_spin_lock,flags);

       return 0;

}

3.5       The OperatingSystem Timers

3.5.1         Function mctl_enable_power_led_flip_hardware

Please refer to document [1] P418 Section 11.4 fordetails.

static void mctl_enable_power_led_flip_hardware(void)

{

       if ( power_led_flip_interval== 0 )

              return;

       // set pin to ostimer 10chout 0

       pxa3xx_mfp_set_afds(POWER_GREEN_LED_GPIO, MFP_AF6, MFP_DS01X);//Please refer to section 3.4.3

//#definePOWER_GREEN_LED_GPIO       (MFP_PIN_GPIO19)

//#define       MFP_PIN_GPIO19        ((0x02BC << 16) | (19))

//From document [1]Section 4.7.3, you may found that the PIN is GPIO19;and then in document [1] Section 4.4 (P76) you may found the function multiplexer of this PIN, in our case itshould be CHOUT0, which is 6.

       OMCR10 = 0; //Reset channel 10

       OSMR10 = power_led_flip_interval; //Setthe time match register of channel 10.

       OSCR10 = 0;            //reset counter value;

       OMCR10 = ( OMCR_R | OMCR_P | OMCR_C | OMCR_CRES_SEC ); // OMCR_R means reset the timer on match, OMCR_P means it isa periodic timer, OMCR_C means channel to match against is OSCRx, OMCR_CRES_SECis 3 (0X11), and therefore means the counter resolution is 1 second.

       OSCR10 = 0;            //set again to trigger the counting.

}

3.5.2         How to Find the Meaning of Multi-Function Pin

From the above section, we can understand how tofind the meaning of MFP.

First, from the codes, you can get the address ofthis PIN;

Then go into document [1] Section 4.7.3,find the name of this PIN;

Then go into document [1] Section 4.4, find themultiplexed function of this named PIN;

Then go into document [1] Section 4.11, to checkout how to set the register.

4.              Future Works

I do not know if following works are necessary:

5.              Questions

6.              References

[1]. <!-- /* Font Definitions */ @font-face{font-family:宋体;panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-alt:SimSun;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;}@font-face{font-family:"/@宋体";panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal{mso-style-parent:"";margin:0cm;margin-bottom:.0001pt;line-height:12.0pt;mso-pagination:none;text-autospace:none;font-size:10.0pt;font-family:"Times New Roman";mso-fareast-font-family:宋体;mso-fareast-language:EN-US;} /* Page Definitions */ @page{mso-page-border-surround-header:no;mso-page-border-surround-footer:no;}@page Section1{size:612.0pt 792.0pt;margin:72.0pt 90.0pt 72.0pt 90.0pt;mso-header-margin:36.0pt;mso-footer-margin:36.0pt;mso-paper-source:0;}div.Section1{page:Section1;}-->PXA3xx_Processor_Family_Developer_Manual_Vol._I_Version_1.0_Rev._C.pdf

 

原创粉丝点击