10 Replies Latest reply on Nov 6, 2014 6:06 PM by airdamien

    gpio-leds registration/devicetree

    airdamien

      Designed a board that adds gpio leds to the edison. Built a test circuit, leds work great.

      I'm used to the arm side of linux/u-boot, it doesn't appear the edison uses devicetree?

      How do I map the gpios to a kernel driven led such as heartbeat?

       

      Thanks!

        • 1. Re: gpio-leds registration/devicetree
          Intel_Alvarado

          Hi airdamien,

          I’d suggest you to take a look at this post https://communities.intel.com/message/230038#230038 , you might find it useful.

          Regards

          Sergio

          • 2. Re: gpio-leds registration/devicetree
            mhahn

            I would assume that's something udev can do? You'd have to write a rule in /etc/udev/rules.d/

            • 3. Re: gpio-leds registration/devicetree
              mmi

              I think the first requirement is a proper device tree configuration and the second one is activation of the kernel modules which provide special led effects like heartbeat, mmc access, cpu load, etc.

               

              rgds, mmi

              • 4. Re: gpio-leds registration/devicetree
                airdamien

                I have the modules. The problem is the modules expect devicetree, and I'm not figuring out how to do it without it. I've built some 3.2 kernels for other embedded boards we've built. And we'd just modify a prime "board.c" file in the kernel source to include the hardware changes. it appears that this platform spread the love among many files.

                • 5. Re: gpio-leds registration/devicetree
                  airdamien

                  Something along these lines, leds covered towards the bottom. trying to get the board.c to register them.  Anybody have a handy way to reference the gpio addresses? The gpio_to_pin is a TI'ism I'm pretty sure.

                   

                   

                   

                  http://elinux.org/images/f/f2/Supporting_200_Different_Expansionboards_The_Broken_Promise_of_Devicetree.pdf

                  edison-src/build/tmp/work/edison-poky-linux/linux-yocto/3.10.17+gitAUTOINC+6ad20f049a_c03195ed6e-r0/linux/arch/x86/platform/intel-mid/board.c

                   

                   

                           &wifi_platform_data_fastirq},

                   

                          /* I2C devices*/

                          {"pcal9555a-1", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},

                          {"pcal9555a-2", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},

                          {"pcal9555a-3", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},

                          {"pcal9555a-4", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},

                   

                          /* SPI devices */

                          {"spidev", SFI_DEV_TYPE_SPI, 0, &spidev_platform_data, NULL},

                          {"ads7955", SFI_DEV_TYPE_SPI, 0, &ads7955_platform_data, NULL},

                          {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data, NULL},

                          {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data, NULL},

                          {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data,

                                                          &ipc_device_handler},

                          {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data, NULL},

                          {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data, NULL},

                          {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data, NULL},

                          {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data, NULL},

                          {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data, NULL},

                          {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data, NULL},

                          {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data,

                                                          &ipc_device_handler},

                          {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data, NULL},

                          {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data, NULL},

                   

                          /* MSIC subdevices */

                          {"msic_adc", SFI_DEV_TYPE_IPC, 1, &msic_adc_platform_data,

                                                                  &ipc_device_handler},

                          {"bcove_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data,

                                                          &ipc_device_handler},

                          {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data,

                                                          &ipc_device_handler},

                          {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data,

                                                          &ipc_device_handler},

                          {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data,

                                                          &ipc_device_handler},

                          {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data,

                                                          &ipc_device_handler},

                          {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data,

                                                          &ipc_device_handler},

                          {"bcove_bcu", SFI_DEV_TYPE_IPC, 1, &mrfl_ocd_platform_data,

                                                          &ipc_device_handler},

                          {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data,

                                                          &ipc_device_handler},

                          {"bcove_adc", SFI_DEV_TYPE_IPC, 1, &bcove_adc_platform_data,

                                                          &ipc_device_handler},

                          {"bcove_thrm", SFI_DEV_TYPE_IPC, 1, &mrfl_thermal_platform_data,

                                                          &ipc_device_handler},

                   

                          /* IPC devices */

                          {"pmic_charger", SFI_DEV_TYPE_IPC, 1, &no_platform_data, NULL},

                          {"pmic_ccsm", SFI_DEV_TYPE_IPC, 1, &mrfl_pmic_ccsm_platform_data,

                                                                  &ipc_device_handler},

                          {"i2c_pmic_adap", SFI_DEV_TYPE_IPC, 1, &mrfl_pmic_i2c_platform_data,

                                                                  &ipc_device_handler},

                          {"soc_thrm", SFI_DEV_TYPE_IPC, 1, &no_platform_data,

                                                                  &soc_thrm_device_handler},

                          {},

                  };

                   

                  static struct gpio_led gpio_leds[] = {

                          {

                                  .name                   = "am335x:EVM_SK:usr0",

                                  .gpio                   = GPIO_TO_PIN(3, 15),   /* D1 */

                          },

                          {

                                  .name                   = "am335x:EVM_SK:usr1",

                                  .gpio                   = GPIO_TO_PIN(3, 14),   /* D2 */

                          },

                          {

                                  .name                   = "am335x:EVM_SK:mmc0",

                                  .gpio                   = GPIO_TO_PIN(3, 16),   /* D3 */

                                  .default_trigger        = "mmc0",

                          },

                          {

                                  .name                   = "am335x:EVM_SK:heartbeat",

                                  .gpio                   = GPIO_TO_PIN(3, 17),   /* D4 */

                                  .default_trigger        = "heartbeat",

                          },

                  };

                   

                  static struct gpio_led_platform_data gpio_led_info = {

                          .leds           = gpio_leds,

                          .num_leds       = ARRAY_SIZE(gpio_leds),

                  };

                   

                  static void gpio_led_init(int evm_id, int profile)

                  {

                          int err;

                          printk("gpio_led_init\n");

                   

                         // setup_pin_mux(gpio_led_mux);

                          err = platform_device_register(&leds_gpio);

                          if (err)

                                  pr_err("failed to register gpio led device\n");

                  }

                  • 6. Re: gpio-leds registration/devicetree
                    airdamien

                    fwiw, the gpio names in the os are 44 45 165 128

                    • 7. Re: gpio-leds registration/devicetree
                      mmi

                      Airdamien,

                      i'm also not familiar how to patch this in the kernel. The DTBs are very new stuff and i guess only latest versions of the kernel support this but not 3.10.

                      Maybe it helps to take a look into the RPi kernel sources. There are these features builtin and the led triggers should be usable for any gpio and in best case you have only to change (and expand)  the port numbers.

                      • 8. Re: gpio-leds registration/devicetree
                        airdamien

                        For anybody that's built their own embedded arm board before DT, it's amazing. It blew out all the 'having to sit and write a program to initialize the board and telling the kernel what hardware is where'  to a standard layout that only describes what is where.  Fairly disappointing that intel didn't take advantage of this upfront. It'd make building your own add-on boards with an edison at the heart a breeze.   As for leds, I've done it the old way, and they're working. I'll post up the solution in a bit.

                        • 9. Re: gpio-leds registration/devicetree
                          airdamien

                          So here's an example, I extended gpio_keys to also do gpio-leds marriage. I stole one of the uart2 pins to use as a gpio, so I jammed a different pin int hsu.c as shown, so it's available for gpio-leds. Haven't figured out where the muxmodes are being set, so I still need to "echo "mode0" >  /sys/kernel/debug/gpio_debug/gpio128/current_pinmux" on boot to make that last led usable. I can probably copy the init code from platform_hsu for it.

                           

                          airdamien@edibuild:~/edison-src/build/tmp/work/edison-poky-linux/linux-yocto/3.10.17+gitAUTOINC+6ad20f049a_c03195ed6e-r0/linux/arch/x86/platform/intel-mid/device_libs$ diff platform_hsu.c ORIGplatform_hsu.c

                          60c60

                          < .cts_gpio = 46,

                          ---

                          > .cts_gpio = 128,

                           

                          airdamien@edibuild:~/edison-src/build/tmp/work/edison-poky-linux/linux-yocto/3.10.17+gitAUTOINC+6ad20f049a_c03195ed6e-r0/linux/arch/x86/platform/intel-mid/device_libs$ cat platform_gpio_keys.c

                          /*

                          * platform_gpio_keys.c: gpio_keys platform data initilization file

                          *

                          * (C) Copyright 2008 Intel Corporation

                          * Author:

                          *

                          * This program is free software; you can redistribute it and/or

                          * modify it under the terms of the GNU General Public License

                          * as published by the Free Software Foundation; version 2

                          * of the License.

                          */

                           

                          #include <linux/input.h>

                          #include <linux/init.h>

                          #include <linux/kernel.h>

                          #include <linux/gpio.h>

                          #include <linux/gpio_keys.h>

                          #include <linux/platform_device.h>

                          #include <asm/intel-mid.h>

                          #include "platform_gpio_keys.h"

                          #include <linux/leds.h>

                           

                          /*

                          * we will search these buttons in SFI GPIO table (by name)

                          * and register them dynamically. Please add all possible

                          * buttons here, we will shrink them if no GPIO found.

                          */

                          static struct gpio_keys_button gpio_button[] = {

                                  {

                                          .code = KEY_POWER,

                                          .gpio = -1, /* GPIO number */

                                          .active_low = 1,

                                          .desc = "power_btn",/*Button description*/

                                          .type = EV_KEY,

                                          .wakeup = 0,

                                          .debounce_interval = 3000,

                                  },

                                  {

                            .code = KEY_PROG1,

                            .gpio = 61,

                            .active_low = 1,

                            .desc = "SW1UI4",

                            .type = EV_KEY,

                            .wakeup = 0,

                            .debounce_interval = 50,

                                  },

                          };

                           

                          static struct gpio_keys_platform_data gpio_keys = {

                            .buttons = gpio_button,

                            .rep = 1,

                            .nbuttons = -1, /* will fill it after search */

                          };

                           

                          static struct platform_device pb_device = {

                            .name = DEVICE_NAME,

                            .id = -1,

                            .dev = {

                            .platform_data = &gpio_keys,

                            },

                          };

                           

                          /*

                          * Shrink the non-existent buttons, register the gpio button

                          * device if there is some

                          static int __init pb_keys_init(void)

                          */

                          //static int pb_keys_init(void)

                          //late_initcall(pb_keys_init);

                           

                          static struct gpio_led gpio_leds[] = {

                                  {

                                          .name                   = "heartbeat",

                                          .gpio                   = 165,  

                                          .default_trigger        = "heartbeat",

                                          .active_low             = true,

                                  },

                                  {

                                          .name                   = "mmc0",

                                          .gpio                   = 44, 

                                          .active_low             = true,

                                          .default_trigger        = "mmc0",

                                  },

                                  {

                                          .name                   = "usr0",

                                          .gpio                   = 45,

                                          .active_low             = true,

                                          .default_trigger        = "heartbeat",

                                  },

                                  {

                                          .name                   = "usr1",

                                          .gpio                   = 128,

                                          .active_low             = true,

                                          .default_trigger        = "heartbeat",

                                  },

                          };

                           

                          static struct gpio_led_platform_data gpio_led_info = {

                                  .leds           = gpio_leds,

                                  .num_leds       = ARRAY_SIZE(gpio_leds),

                          };

                           

                          static struct platform_device leds_gpio = {

                                  .name   = "leds-gpio",

                                  .id     = -1,

                                  .dev    = {

                                          .platform_data  = &gpio_led_info,

                                  },

                          };

                           

                          //static void __init gpio_led_init(int evm_id, int profile)

                          static void __init gpio_led_init(void)

                          {

                                  int err;

                                   //pb_keys_init;

                                  //setup_pin_mux(gpio_led_mux);

                                  printk("gpio_led_init\n");

                                  err = platform_device_register(&leds_gpio);

                                  if (err)

                                          printk("failed to register gpio led device\n");

                          }

                           

                          //late_initcall(gpio_led_init);

                           

                          static int __init pb_keys_init(void)

                          {

                            struct gpio_keys_button *gb = gpio_button;

                            int i, num, good = 0;

                           

                            num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);

                            for (i = 0; i < num; i++) {

                            pr_info("info[%2d]: name = %s, gpio = %d\n",

                            i, gb[i].desc, gb[i].gpio);

                            if (gb[i].gpio == -1)

                            continue;

                           

                            if (i != good)

                            gb[good] = gb[i];

                            good++;

                            }

                           

                            //int err;

                                  //err = platform_device_register(&leds_gpio);

                                  //if (err)

                                  //        printk("failed to register gpio led device\n");

                           

                            if (good) {

                            gpio_keys.nbuttons = good;

                            return platform_device_register(&pb_device);

                            }

                            return 0;

                          }

                          late_initcall(pb_keys_init);

                          late_initcall(gpio_led_init);

                          • 10. Re: gpio-leds registration/devicetree
                            airdamien

                            forced it to remux on boot in platform_hsu.c just look at the line with 128 in it.

                             

                             

                            static void hsu_port_enable(int port)

                            {

                                    struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;

                             

                                    if (info->rx_gpio) {

                                            lnw_gpio_set_alt(info->rx_gpio, info->rx_alt);

                                            gpio_direction_input(info->rx_gpio);

                                    }

                                    if (info->tx_gpio) {

                                            gpio_direction_output(info->tx_gpio, 1);

                                            lnw_gpio_set_alt(info->tx_gpio, info->tx_alt);

                                            usleep_range(10, 10);

                                            gpio_direction_output(info->tx_gpio, 0);

                             

                                    }

                                    if (info->cts_gpio) {

                                            lnw_gpio_set_alt(info->cts_gpio, info->cts_alt);

                                            gpio_direction_input(info->cts_gpio);

                                            lnw_gpio_set_alt(128, 0);

                                    }

                                    if (info->rts_gpio) {

                                            gpio_direction_output(info->rts_gpio, 0);

                                            lnw_gpio_set_alt(info->rts_gpio, info->rts_alt);

                                    }

                            }