Hybrid Equipment LED Driver Analysis
/*******************************
*
* Miscellaneous device driver: Miscdevice
*majior=10;
*
* *****************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/moduleparam.h>//#include memory allocation functions such as <linux/slab.h>//kcalloc,kzalloc
---------IOCTL------------
#include <linux/ioctl.h>
---------Misc_register----
#include <linux/miscdevice.h>
----------Cdev--------------
#include <linux/cdev.h>
----------Delay-------------
#include <linux/delay.h>
----------GPIO---------------
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#define S3c_gpio_special_mark (0XFFFFFFF0)
#define S3C_GPIO_SPECIAL (x) (S3c_gpio_special_mark | (x)) Kernel definition
#define DEVICE_NAME "LEDs"
static int led_gpios[] = {
S5PV210_MP04 (4),
S5PV210_MP04 (5),
S5PV210_MP04 (6),
S5PV210_MP04 (7),
};//4 an LED
#define Led_num array_size (Led_gpios)
Static long fl210_leds_ioctl (struct file *filp, unsigned int cmd,
unsigned long Arg)
{
Switch (CMD) {
Case 0:
Case 1:
if (Arg > Led_num) {
Return-einval;
}
Gpio_set_value (Led_gpios[arg],!cmd);//Set the led to fade according to CMD
PRINTK (device_name ":%ld%d\n", ARG, CMD);
Break
Default
Return-einval;
}
return 0;
}
static struct File_operations Fl210_led_dev_fops = {
. Owner = This_module,
. Unlocked_ioctl = Fl210_leds_ioctl,
};
----------------miscdevice------------------static struct Miscdevice Fl210_led_dev = {
. minor = Misc_dynamic_minor,
. Name = Device_name,
. FoPs = &fl210_led_dev_fops,
};//--------------------------------------------
static int __init fl210_led_dev_init (void) {
int ret;
int i;
for (i = 0; i < Led_num; i++) {
ret = Gpio_request (Led_gpios[i], "led");//Application Gpio Port
if (ret) {
PRINTK ("%s:request GPIO%d for LED failed, ret =%d\n", Device_name,
Led_gpios[i], ret);
return ret;
}
S3c_gpio_cfgpin (Led_gpios[i], s3c_gpio_output);//set Gpio port as output
Gpio_set_value (Led_gpios[i], 1);//Initialize the value of the Gpio port
}
ret = Misc_register (&fl210_led_dev);//Register Miscellaneous devices
PRINTK (device_name "\tinitialized\n");
PRINTK ("Led num is:%d\n", led_num);
return ret;
}
static void __exit fl210_led_dev_exit (void) {
int i;
for (i = 0; i < Led_num; i++) {
Gpio_free (Led_gpios[i]);//release Gpio port
}
Misc_deregister (&fl210_led_dev);//Logout device
}
Module_init (Fl210_led_dev_init);
Module_exit (Fl210_led_dev_exit);
Module_license ("GPL");
Module_author ("");
S5PV210_MP04 macro defined in Linux/arch/arm/mach-s5pv210/include/mach/gpio.h
#define S5PV210_MP04 (_NR) (S5pv210_gpio_mp04_start + (_NR))
S5pv210_gpio_mp04_start = S5pv210_gpio_next (S5PV210_GPIO_MP03),
#define S5PV210_GPIO_NEXT (__gpio) \ ((__gpio# #_START) + (__gpio# #_NR) + config_s3c_gpio_space + 1)
The CONFIG_S3C_GPIO_SPAC here is the kernel configuration option, which can be found in. config and my configuration is: Config_s3c_gpio_space = 0
The code above uses several functions:
Gpio_set_value ();
S3c_gpio_cfgpin ();
Gpio_request ();
Gpio_free ();
Misc_register ();
Misc_deregister ();
The following will be analyzed individually.
The test procedure is as follows:
#include <stdio.h>//#include "sys/types.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>//read,write et cetera//#include "termios.h"//#include "sys/stat.h"
#include <fcntl.h>
#define LED2_ON 0x1#define Led2_off 0x0
Main (int Argc,char *argv[])
{
int FD;
if (Fd=open ("/dev/leds", O_rdwr/*| O_ndelay | o_noctty*/)) < 0)
{
printf ("Open Device failed.\r\n");
Exit (1);
}
Else
{
printf ("Open Device successed.\r\n");
}
if (argc<3)
{
/* Code */
printf ("Usage:%s <on|off num>\n", argv[0]);
Exit (1);
}
if (!strcmp (argv[1], "on"))
{
printf ("Led1 'll on!! \ n ");
if (IOCTL (Fd,led2_on,atoi (argv[2)) <0)
{
}
}
if (!strcmp (argv[1], "off"))
{
printf ("Led1 'll off!! \ n ");
if (IOCTL (Fd,led2_off,atoi (argv[2)) <0)
{
printf ("Ioctl err!! \ n ");
}
}
Close (FD);
}
First look at S3c_gpio_cfgpin ();
int s3c_gpio_cfgpin (unsigned int pin, unsigned int config)
{
struct S3c_gpio_chip *chip = s3c_gpiolib_getchip (PIN),//get the corresponding gpio struct first pointer, which contains the various parameters of the Gpio
unsigned long flags;
int offset;
int ret;
if (!chip)
Return-einval;
offset = pin-chip->chip.base;
S3c_gpio_lock (chip, flags);
RET = S3C_GPIO_DO_SETCFG (chip, offset, config);//Set the value of the Gpio status Register as Config
S3c_gpio_unlock (chip, flags);
return ret;
}
Static inline struct s3c_gpio_chip *s3c_gpiolib_getchip (unsigned int chip)
{
Return (Chip < s3c_gpio_end)? S3c_gpios[chip]: NULL;
}
static inline int s3c_gpio_do_setcfg (struct s3c_gpio_chip *chip,
unsigned int off, unsigned int config)
{
Return (Chip->config->set_config) (chip, off, config);
}
static struct S3c_gpio_cfg gpio_cfg = {
. Set_config = S3c_gpio_setcfg_s3c64xx_4bit,
. Set_pull = S3c_gpio_setpull_updown,
. Get_pull = S3c_gpio_getpull_updown,
};
int s3c_gpio_setcfg_s3c64xx_4bit (struct s3c_gpio_chip *chip,
unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base;
unsigned int shift = (off & 7) * 4;
U32 con;
if (Off < 8 && Chip->chip.ngpio > 8)
Reg-= 4;
if (s3c_gpio_is_cfg_special (CFG)) {
CFG &= 0xf;
CFG <<= shift;
}
con = __RAW_READL (reg);//Read Gpxcon value
Con &= ~ (0xf << shift);//zeroing
Con |= cfg;//setting config
__raw_writel (Con, reg);//write value
return 0;
}
The structure of the body s3c_gpio_chip as follows:
*/struct S3c_gpio_chip {
struct gpio_chip chip;
struct S3C_GPIO_CFG *config;
struct S3C_GPIO_PM *pm;
void __iomem *base;
int eint_offset;
spinlock_t lock;
#ifdef CONFIG_PM
U32 pm_save[7]; #endif
};
static struct S3c_gpio_chip s5pv210_gpio_4bit[] = {//description of all GPIO ports in the chip
{
. Chip = {
. Base = s5pv210_gpa0 (0),
. Ngpio = S5pv210_gpio_a0_nr,
. Label = "GPA0",
. TO_IRQ = S5p_gpiolib_gpioint_to_irq,
},
},{
。。。。
}
。。。。
};
Next look at Gpio_set_value ();
void __gpio_set_value (unsigned gpio, int value)
{
struct Gpio_chip *chip;
Chip = Gpio_to_chip (GPIO);//Returns the Gpio_desc[pin].chip pointer warn_on (extra_checks && chip->can_sleep) corresponding to the pin;
Chip->set (Chip, gpio-chip->base, value);//Call Chip->set
}
LED Driver Analysis