单片机
返回首页

字符设备驱动(1)代码分析---之gpio_get_value

2025-02-05 来源:cnblogs

在中断处理函数中,调用gpio_get_value/gpio_set_value()函数来获取/设置gpio端口的值,在这里简单分析一下内核的实现流程。


tmp = gpio_get_value(S5PV210_GPH2(0));

#define gpio_get_value    __gpio_get_value

int __gpio_get_value(unsigned gpio)

{

    struct gpio_chip    *chip;

    int value;

    chip = gpio_to_chip(gpio);

    

    

    ##

        {

         .base    = (S5P_VA_GPIO + 0xC40),

         .config    = &gpio_cfg_noint,

         .irq_base = IRQ_EINT(16),

            .chip    = {

            .base    = S5PV210_GPH2(0),

            .ngpio    = S5PV210_GPIO_H2_NR,

            .label    = 'GPH2',

            .to_irq = samsung_gpiolib_to_irq,

        },

    ##

    

    

    value = chip->get ? chip->get(chip, gpio - chip->base) : 0;

    //offset = gpio - chip->base

    trace_gpio_value(gpio, 1, value);

    return value;

    

    ##

/****************************************************

    chip->get()函数的内核实现

****************************************************/

    //drivers/gpio/gpio-plat-samsung.c

    void __init samsung_gpiolib_add_4bit_chips

            (structs 3c_gpio_chip *chip,int nr_chips)

    {

        for (; nr_chips > 0; nr_chips--, chip++) {

            samsung_gpiolib_add_4bit(chip);

            s3c_gpiolib_add(chip);

        }

    }


    void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)

    {

        chip->chip.direction_input = samsung_gpiolib_4bit_input;

        chip->chip.direction_output = samsung_gpiolib_4bit_output;

        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);

    }

    

    //arch/arm/plat_samsung/gpio.c

    __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)

    {

        struct gpio_chip *gc = &chip->chip;    

        int ret;

        ....

        ....

        

        if (!gc->direction_input)

            gc->direction_input = s3c_gpiolib_input;

        if (!gc->direction_output)

            gc->direction_output = s3c_gpiolib_output;

        if (!gc->set)

            gc->set = s3c_gpiolib_set;

        

        if (!gc->get)

            gc->get = s3c_gpiolib_get;

        //至此完善后的结构体gc变为:


  gc = {

         .base    = (S5P_VA_GPIO + 0xC40),

         .config    = &gpio_cfg_noint,

         .irq_base = IRQ_EINT(16),

         .pm = __gpio_pm(&s3c_gpio_pm_4bit),

            .chip    = {

            .base    = S5PV210_GPH2(0),

            .ngpio    = S5PV210_GPIO_H2_NR,

            .label    = 'GPH2',

            .to_irq = samsung_gpiolib_to_irq,

            .direction_input = samsung_gpiolib_4bit_input,

            .direction_output = samsung_gpiolib_4bit_output,

            .set = s3c_gpiolib_set,

            .get = s3c_gpiolib_get,

            },


         ###


//samsung_gpiolib_4bit_input具体实现函数


 static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,

                      unsigned int offset)

            {

                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);

                void __iomem *base = ourchip->base;

                unsigned long con;


                con = __raw_readl(base + GPIOCON_OFF);

                con &= ~(0xf << con_4bit_shift(offset));

                __raw_writel(con, base + GPIOCON_OFF);


                gpio_dbg('%s: %p: CON now %08lxn', __func__, base, con);


                return 0;

            }


static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,

                                   unsigned int offset, int value)

            {

                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);

                void __iomem *base = ourchip->base;

                unsigned long con;

                unsigned long dat;


                con = __raw_readl(base + GPIOCON_OFF);

                con &= ~(0xf << con_4bit_shift(offset));

                con |= 0x1 << con_4bit_shift(offset);


                dat = __raw_readl(base + GPIODAT_OFF);


                if (value)

                    dat |= 1 << offset;

                else

                    dat &= ~(1 << offset);

                //有点小疑问:为啥要写两次数据???

                __raw_writel(dat, base + GPIODAT_OFF);

                __raw_writel(con, base + GPIOCON_OFF);

                __raw_writel(dat, base + GPIODAT_OFF);


                gpio_dbg('%s: %p: CON %08lx, DAT %08lxn', __func__, base, con, dat);


                return 0;

            }


    //s3c_gpiolib_set、s3c_gpiolib_get的具体实现函数



static void s3c_gpiolib_set(struct gpio_chip *chip,

                unsigned offset, int value)

            {

                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);

                void __iomem *base = ourchip->base;

                unsigned long flags;

                unsigned long dat;


                s3c_gpio_lock(ourchip, flags);


                dat = __raw_readl(base + 0x04);

                //将需要设定的位清零

                dat &= ~(1 << offset);

                //如果设定的值是1,则将相应位置1

                if (value)

                    dat |= 1 << offset;

                __raw_writel(dat, base + 0x04);


                s3c_gpio_unlock(ourchip, flags);

            }


static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset)

            {

                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);

                unsigned long val;


                val = __raw_readl(ourchip->base + 0x04);

                //将需要获取的位右移至最低位

                val >>= offset;

                //获取最低位的值并返回

                val &= 1;

                return val;

            }


                    

        ###

        

        ....

    }

    ##

    

    

}


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦四级调频发射机

  • 500W MOS场效应管电源逆变器,12V转110V/220V

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • 12V转110V/220V 500W逆变器

  • DS1669数字电位器

    相关电子头条文章