Device Tree Examples
Device Tree Examples
}; //root node
&am33xx_pinmux {
p8_gpios: bone_p8_gpios {
pinctrl-single,pins = <
AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA1,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA2,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA3,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA4,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA5,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA6,PIN_OUTPUT,MUX_MODE7)
>;
};
};
static ssize_t lcdscroll_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lcd_private_data *dev_data = dev_get_drvdata(dev);
if(dev_data->lcd_scroll)
ret = sprintf(buf, "%s\n", "on");
else
ret = sprintf(buf, "%s\n", "off");
return ret;
}
if (sysfs_streq(buf, "on")){
dev_data->lcd_scroll = 1;
/*Display shift left */
lcd_send_command(0x18,dev);
}
else if (sysfs_streq(buf, "off")){
dev_data->lcd_scroll = 0;
/*return home */
lcd_send_command(0x2,dev);
/*Turn off display shift */
lcd_send_command(0x10,dev);
}
else
status = -EINVAL;
return status ? : size;
}
static DEVICE_ATTR_RW(lcdscroll);
static struct attribute *lcd_attrs[] = {
&dev_attr_lcdcmd.attr,
&dev_attr_lcdtext.attr,
&dev_attr_lcdscroll.attr,
&dev_attr_lcdxy.attr,
NULL
};
static ssize_t lcdxy_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int status;
struct lcd_private_data *dev_data = dev_get_drvdata(dev);
status = sprintf(buf,"%s\n",dev_data->lcdxy);
return status;
}
static ssize_t lcdxy_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
{
long value;
int status;
int x, y;
struct lcd_private_data *dev_data = dev_get_drvdata(dev);
status = kstrtol(buf,10,&value);
if(status)
return status;
x = value /10;
y = value % 10;
status = sprintf(dev_data->lcdxy ,"(%d,%d)",x,y);
lcd_set_cursor(x,y,dev);
return status;
dev_set_drvdata(dev,&lcd_data);
lcd_data.dev = device_create_with_groups(drv_data.class_lcd,dev,0,\
lcd_data,lcd_attr_groups,"LCD16x2");
}
Example 2:
compatible = "org,bone-gpio-sysfs";
pinctrl-single,names = "default";
pinctrl-0 = <&p8_gpios>;
status = "disabled";
gpio1 {
label = "gpio2.2";
bone-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
};
gpio2 {
label = "gpio2.7";
bone-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
};
led1 {
label = "usrled1:gpio1.22";
bone-gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
};
led2 {
label = "usrled2:gpio1.23";
bone-gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
};
};//bone_gpio_devs
}; //root node
&am33xx_pinmux {
p8_gpios: bone_p8_gpios {
pinctrl-single,pins = <
AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA1,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA2,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA3,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA4,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA5,PIN_OUTPUT,MUX_MODE7)
AM33XX_PADCONF(AM335X_PIN_LCD_DATA6,PIN_OUTPUT,MUX_MODE7)
>;
};
};
Driver changes:
dir = gpiod_get_direction(dev_data->desc);
/* if dir = 0 , then show "out". if dir =1 , then show "in" */
direction = (dir == 0) ? "out":"in";
return sprintf(buf,"%s\n",direction);
ssize_t direction_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count) {
struct gpiodev_private_data *dev_data = dev_get_drvdata(dev);
if(sysfs_streq(buf,"in") )
ret = gpiod_direction_input(dev_data->desc);
else if (sysfs_streq(buf,"out"))
ret = gpiod_direction_output(dev_data->desc,0);
return ret ? : count;
}
ssize_t value_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count) {
struct gpiodev_private_data *dev_data = dev_get_drvdata(dev);
ret = kstrtol(buf,0,&value);
gpiod_set_value(dev_data->desc,value);
return count;
}
static DEVICE_ATTR_RW(direction);
static DEVICE_ATTR_RW(value);
static DEVICE_ATTR_RO(label);
if(of_property_read_string(child,"label",&name) )
{
dev_warn(dev,"Missing label information\n");
snprintf(dev_data->label,sizeof(dev_data->label),"unkngpio%d",i);
}else{
strcpy(dev_data->label,name);
dev_info(dev,"GPIO label = %s\n",dev_data->label);
}
dev_data->desc = devm_fwnode_get_gpiod_from_child(dev,"bone",&child->fwnode,\
GPIOD_ASIS,dev_data->label);
leds {
compatible = "gpio-leds";
user {
label = "green";
gpios = <0x13 0x1 0x0>;
linux,default-trigger = “heartbeat”;
};
};
Here we have a node labeled “leds” which has a property saying it is compatible with the “gpio-leds”
driver. If we reference the documentation for the gpio-leds driver here, we see that each subnode (in
our case “user”) is a controllable LED which appears as an entry in the ‘/sys/class/leds/’ directory with a
name specified by the “label” property.
he GPIO bank is specified with a pointer handle (or phandle in device tree language) to a GPIO bank
node. If we search for “phandle = <0x13>” in the ‘dts’ file we find the node for Freescale MXS
compatible GPIO controller:
gpio@2 {
compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
interrupts = <0x12>;
gpio-controller;
#gpio-cells = <0x2>;
interrupt-controller;
#interrupt-cells = <0x2>;
linux,phandle = <0x13>;
phandle = <0x13>;
};
Example 4
humidity_sensor {
compatible = "dht11";
gpios = <0x11 19 0x0>;
};
Example 5
https://www.kernel.org/doc/html/latest/driver-api/gpio/board.html
Driver changes:
struct gpio_desc *red, *green, *blue, *power;
Beaglebone: Introduction to GPIOs - Using Device Tree Overlays under Linux 3.8+
GPIO Debouncing:
Debouncing in practice involves setting up a timer when something happens on the line, wait a little
while and then sample the line again, so see if it still has the same value (low or high). This could also be
repeated by a clever state machine, waiting for a line to become stable. In either case, it sets a certain
number of milliseconds for debouncing, or just “on/off” if that time is not configurable.
Ideally the gpio controller will have debounce support, so the gpio controller provides a wrapper
function for it gpio_set_debounce(). If your controller supports it should return 0. Also if debounce is
not supported by controller, software debounce can be added for example gpio_keys
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
ledOn = !ledOn; // Invert the LED state on each button press
gpiod_set_value(gpioLED, ledOn); // Set the physical LED accordingly
getnstimeofday(&ts_current); // Get the current time as ts_current
ts_diff = timespec_sub(ts_current, ts_last); // Determine the time difference between last 2 presses
ts_last = ts_current; // Store the current time as the last time ts_last
printk(KERN_INFO "EBB Button: The button state is currently: %d\n", gpio_get_value(gpioButton));
numberPresses++; // Global counter, will be outputted when the module is unloaded
return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
}
Software Debouncing:
printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered, jiffies=%lu, diff=%lu, direction: %d
\n",
irq, (char *) dev_id, jiffies, diff, gpio_get_value(GPIO_BUTTON1));
old_jiffie = jiffies;
return IRQ_HANDLED;
}
More Example of DT LED node:
leds {
compatible = "gpio-leds";
led0 {
gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>;
linux,default-trigger = "disk-activity";
function = LED_FUNCTION_DISK;
};
led1 {
gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>;
/* Keep LED on if BIOS detected hardware fault */
default-state = "keep";
function = LED_FUNCTION_FAULT;
};
};
run-control {
compatible = "gpio-leds";
led0 {
gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>;
color = <LED_COLOR_ID_RED>;
default-state = "off";
};
led1 {
gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>;
color = <LED_COLOR_ID_GREEN>;
default-state = "on";
};
};