Analysis of LED Driver of Marvell (Marvell PXA310 LED驱动代码分析)
2009-12-19 22:41
429 查看
1.
Abstract
抱歉这篇报告是我当初用英文写的,有兴趣的朋友可以参考。2.
Introduction
.3.
Driver Codes
Codes exist indrivers/misc/misc_control.c.
3.1
Data Structure
The devicestructure 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 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 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 fordetails.
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 tofind 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
相关文章推荐
- Analysis of Touch Panel Driver of Marvell (Marvell PXA310触摸屏驱动代码分析)
- Analysis of Keypad Driver of Marvell (Marvell PXA310键盘驱动代码分析)
- Analysis of I2C of Marvell (Marvell PXA310 I2C驱动分析)
- platform s3c2440_led 驱动代码简要分析<1>
- 第四部分 linux led驱动代码分析
- microwindows代码分析 (四)screen driver显示驱动之framebuffer
- LED设备驱动二之重要代码和调试问题分析
- fl2440——驱动学习-LED驱动程序代码分析
- microwindows代码分析 (三)screen driver显示驱动之X11
- fl2440驱动学习——LED驱动代码分析
- linux设备驱动之LED驱动代码分析
- microwindows代码分析 (二)screen driver显示驱动的架构
- Simens NX (原UG)内部代码逆向分析 / Inner code Reverse analysis of NX software
- LeetCode -- Minimum Depth of Binary Tree代码分析
- linux驱动开发: wm8960 codec代码分析
- mini2440 led驱动代码(原创)基于iomap<测试初始化没有问题,其它功能待开发>
- java.lang.OutOfMemoryError原因分析——让代码茁壮成长
- 千兆网口 Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析
- dm9000驱动代码流程分析
- Intel 82599 ixgbe & ixgbevf CNA 卡驱动分析03——部分功能代码分析