Toybrick EN

中文 / EN
Toybrick EN Wiki TB-RK3399ProD How to use a GPIO pin at kernel
How to use a GPIO pin at kernel

All the pins for I/O, usually can work as genernal purpose IO, but you may need to modify the iomux from its default functions. We have leave four pins in GPIO mode for our board, they are GPIO0_A5, GPIO0_A6, GPIO1_B1 and GPIO1_B2。The voltage level of those four pins are 1.8v(CMOS level), you need a DC converter to rise its voltage for those device would use 3.3V voltage level(TTL level).

1.png

Sample

1. Assigned for a exist driver(reset usb hub here)

A sample of device tree:

  1. usbhub_reset: usbhub-reset {
             compatible = "usbhub-reset";
             uhrst-gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
     };

uhrst-gpio:this driver would use the value here to get the handle of its GPIO pin. Driver would call of_get_named_gpio_flags()  to receive its GPIO handle.

“6” stands for its index in a GPIO bank.(We have mutiple banks in a GPIO controller and many pins in a bank. bank=6/8+A;IO=6%8;)

GPIO_ACTIVE_HIGH: This pin would be output high when it is active.

Driver file could be found here

  1. "drivers/usb/misc/usbhub_reset.c"

of_device_id: Struct used for matching a device

platform_driver: struct used for platform device, using platform_driver_register() to register it at module init stage.

What this driver do is quite simple, it would pull down the GPIO pin which assigned with this driver then release it at system is rebooting, this driver use register_reboot_notifier() to register its function to the system reboot chain.

2. Using the pinctrl api

You may refer this document for more detail

A sample of device tree

  1. &dsi {
        reset-gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_LOW>;  /* TC358775_RST */
        enable-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; /* STBY */
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&lcd_bl_en_h>;
                       ......
    };
    &pinctrl {
        tc3587 {
             lcd_bl_en_h: lcd-bl-en-{
                            rockchip,pins =
                                    <1 13 RK_FUNC_GPIO &pcfg_output_high>;
                                  };
            };
               };

pinctrl-names:  The list of names to assign states.

pinctrl-0: List of phandles, each pointing at a pin configuration node.

&pinctrl: the pinmux controller inherited  from its parent device tree file.

tc3587: a name for this pins group;

lcd_bl_en_h: a label for this pin

rockchip,pins: the list of numeric pin ids and their mux settings. Here the GPIO1_B5 is configured to GPIO function and with a default high output.

When there are more than one pin are used in pinctrl, driver would use its name which is defined in pinctrl-name to refer each of them.

  1. pinctrl-names = "default", "pmic-sleep",
                    "pmic-power-off", "pmic-reset";
                    pinctrl-0 = <&pmic_int_l>;
                    pinctrl-1 = <&soc_slppin_slp>, <&rk809_slppin_slp>;
                    pinctrl-2 = <&soc_slppin_gpio>, <&rk809_slppin_pwrdn>;
                    pinctrl-3 = <&soc_slppin_rst>, <&rk809_slppin_rst>;

Here is some sample code in a driver:

① To get a handle of a pin:

rk808->pins->p = devm_pinctrl_get(dev);

To fetch the current state of a pin

default_st = pinctrl_lookup_state(rk808->pins->p, PINCTRL_STATE_DEFAULT);

To set a state to a pin

pinctrl_select_state(rk808->pins->p, default_st);

3. How to configure a GPIO as interrupt source(legacy)

A sample of device tree

  1. gpio {
        compatible = "irq-test-gpio";
        irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>;  /* GPIO4_D5 */
    };

IRQ_TYPE_EDGE_RISING  means we want a interrupt is used when the interupt line is at rising eding

The full IRQ line status definitions:

IRQ_TYPE_NONE        - default, unspecified type
IRQ_TYPE_EDGE_RISING        - rising edge triggered
IRQ_TYPE_EDGE_FALLING    - falling edge triggered
IRQ_TYPE_EDGE_BOTH        - rising and falling edge triggered
IRQ_TYPE_LEVEL_HIGH        - high level triggered
IRQ_TYPE_LEVEL_LOW        - low level triggered

How does it work on driver:

You can register a interrupt at probe() function of a driver, which you get pin assigned with this drive though the device tree.

  1. static int test_gpio_probe(struct platform_device *pdev)
    {  
        int ret;
        int gpio;
        enum of_gpio_flags flag;
        struct test_gpio_info *gpio_info;
        struct device_node * test_gpio_node = pdev->dev.of_node;
        ......
       
        gpio_info-> test_irq_gpio = gpio;
        gpio_info-> test_irq_mode = flag;
        gpio_info-> test_irq = gpio_to_irq(gpio_info-> test_irq_gpio);
        if (gpio_info-> test_irq) {
           if (gpio_request(gpio, "irq-test-gpio")) {
              printk("gpio %d request failed!\n", gpio); gpio_free(gpio); return IRQ_NONE;
            }
            ret = request_irq(gpio_info-> test_irq, test_gpio_irq, flag, "irq-test-gpio", gpio_info);
            if (ret != 0) free_irq(gpio_info-> test_irq, gpio_info);
               dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret);
         }
         return 0;
    }
    static irqreturn_t test_gpio_irq(int irq, void *dev_id)
    {
        printk("Enter irq test gpio irq test program!\n");
        return IRQ_HANDLED;
    }

gpio_to_irq() would, map GPIO numbers to IRQ numbers, then non-error values returned from gpio_to_irq() can be passed to request_irq() or free_irq().  They will often be stored into IRQ resources for platform devices, by the board-specific initialization code.  Note that IRQ trigger options are part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are
system wakeup capabilities.

We use test_gpio_irq() as interrupt handle function here, "irq-test-gpio" is the name of this driver we use it here as unique for the IRQ runtime, gpio_info is the private device data

for this interupt handle which is necessary for those drive may use shared interupt source.


Products Store Community Wiki Download About TB


To Top