您的位置:首页 > 编程语言

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

2009-12-19 22:41 429 查看

1.

Abstract

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

2.

Introduction

.

3.

Driver Codes

Codes exist in
drivers/misc/misc_control.c.

3.1

Data Structure

The device
structure in

3.2

Initialize
Codes

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 we
have 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 bluetooth
chip

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

return 0;

}

3.3

Driver
Operation 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, unsigned
int cmd,

unsigned long arg)

{

int ret;

void __user *argp = (void
__user *)arg;

struct misc_ctl_struct
m_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 current
value, all of them are the current settings

of GPIO


if (ret)

return ret;

return
copy_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 the
LED, 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){

case
CTRL_POWER_RED_LED:


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


break;

case
CTRL_POWER_GREEN_LED:


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



break;

case
CTRL_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 to
2 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 is
set and normal mode is not set. we control led with 0/1 through GPIO in full
power 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 sleep
mode is set, we disable led in full power state.

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

pxa3xx_gpio_set_level(POWER_GREEN_LED_GPIO,0);

return 0;

}

return -EINVAL;

}

3.4

The Pin
Descriptions

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



unsigned
int 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 for
concrete 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 function
pxa3xx_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 void
mctl_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 of
it: GPIO_19. See the explanation in Section 3.5



}

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


{

//ds
is 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 is
started 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 DRV
fields, 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 Operating
System Timers

3.5.1

Function mctl_enable_power_led_flip_hardware

Please refer to document [1] P418 Section 11.4 for
details.

static void mctl_enable_power_led_flip_hardware(void)

{

if ( power_led_flip_interval
== 0 )

return;

// set pin to ostimer 10
chout 0


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



//#define
POWER_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 it
should be CHOUT0, which is 6.



OMCR10 = 0; //Reset channel 10




OSMR10 = power_led_flip_interval; //Set
the 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 is
a periodic timer, OMCR_C means channel to match against is OSCRx, OMCR_CRES_SEC
is 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 to
find the meaning of MFP.

First, from the codes, you can get the address of
this 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 the
multiplexed function of this named PIN;

Then go into document [1] Section 4.11, to check
out 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: