Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Driver allowing to define GPIO pin groups and control them via sysfs

26 views
Skip to first unread message

Wojciech M. Zabołotny"

unread,
Jan 25, 2018, 11:51:20 AM1/25/18
to
This are the sources of the device driver, allowing you to create the
group of GPIOs, and access them via sysfs.

I have tested it in a system, where two AXI GPIOs were implemented in the
Xilinx MPSoC based design.
In the device tree, the GPIO groups were defined as follows:
&amba_pl {
multigpio {
compatible = "wzab,multi-gpio";
dout1-gpios = <&axi_gpio_0 0 0>,
<&axi_gpio_0 1 0>,
<&axi_gpio_0 2 0>,
<&axi_gpio_0 3 0>,
<&axi_gpio_0 4 0>,
<&axi_gpio_0 5 0>,
<&axi_gpio_0 6 0>,
<&axi_gpio_0 7 0>;
dout2-gpios = <&axi_gpio_0 8 0>,
<&axi_gpio_0 9 0>,
<&axi_gpio_0 10 0>,
<&axi_gpio_0 11 0>,
<&axi_gpio_0 12 0>,
<&axi_gpio_0 13 0>,
<&axi_gpio_0 14 0>,
<&axi_gpio_0 15 0>;
din-gpios = <&axi_gpio_1 0 0>,
<&axi_gpio_1 1 0>,
<&axi_gpio_1 2 0>,
<&axi_gpio_1 3 0>,
<&axi_gpio_1 4 0>,
<&axi_gpio_1 5 0>,
<&axi_gpio_1 6 0>,
<&axi_gpio_1 7 0>;
};
};

Then, after loading the "multi-gpio.ko" module, it was possible to
access GPIOs via shell commands like below:

echo 37 > /sys/class/class_multi_gpio/my_dev0/dout1
cat /sys/class/class_multi_gpio/my_dev0/din
121
echo 17 > /sys/class/class_multi_gpio/my_dev0/dout2

Please note, that this is a quick&dirty, proof of the concept implementation.
However, I hope that somebody may find it useful.
I do not provide any warranty. If you decide to use it, you do it on your own
risk.

Regards,
Wojtek

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh28743
# Made on 2018-01-25 17:43 CET by <wzab@wzdell>.
# Source directory was '/tmp'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 8127 -rw-rw-r-- multi-gpio.c
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= multi-gpio.c ==============
if test -n "${keep_file}" && test -f 'multi-gpio.c'
then
${echo} "x - SKIPPING multi-gpio.c (file already exists)"

else
${echo} "x - extracting multi-gpio.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'multi-gpio.c' &&
/* Driver for grups of pins in AXI GPIO blocks
X *
X * Copyright (C) 2018 by Wojciech M. Zabolotny
X * wzab<at>ise.pw.edu.pl
X * Significantly based on multiple drivers included in
X * sources of Linux
X * Therefore this source is licensed under GPL v2
X */
X
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL v2");
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <asm/uaccess.h>
X
#define SUCCESS 0
#define DEVICE_NAME "multi-gpio"
#define CLASS_NAME "class_multi_gpio"
X
static struct t_dev_state {
X int n_of_dev;
} dev_states;
X
//It is a dirty trick, but we can service only one device :-(
static struct platform_device * my_pdev = NULL;
static dev_t my_dev=0;
static struct cdev *my_cdev = NULL;
static struct class *my_class = NULL;
X
struct gpio_descs *g_dout1 = NULL , *g_dout2 = NULL, *g_din = NULL;
X
//Store result buffer to gpio
static ssize_t gpio_store(struct device *dev, struct gpio_descs *gds, const char *buf, size_t size)
{
X long val;
X int res;
X int i;
X long mask = 1;
X res=kstrtol(buf, 0, &val);
X if(res<0) return res;
X for(i=0;i<gds->ndescs;i++) {
X gpiod_set_value(gds->desc[i],(val & mask) ? 1 : 0);
X mask <<= 1;
X }
X return 0;
}
X
static ssize_t gpio_show(struct gpio_descs *gds, char *buf)
{
X long val=0;
X int res;
X int i;
X long mask = 1;
X for(i=0;i<gds->ndescs;i++) {
X res=gpiod_get_value(gds->desc[i]);
X if(res<0) return res;
X if(res) val |= mask;
X mask <<= 1;
X }
X res=snprintf(buf,PAGE_SIZE,"%ld",val);
X return res;
}
X
X
static ssize_t dout1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
X int res;
X struct t_dev_state * ds = dev_get_drvdata(dev);
X printk(KERN_INFO "dout1 in device %d set to %s\n", ds->n_of_dev,buf);
X res = gpio_store(dev,g_dout1,buf,size);
X if(res<0) return res;
X return size;
}
X
static ssize_t dout2_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
X int res;
X struct t_dev_state * ds = dev_get_drvdata(dev);
X printk(KERN_INFO "dout2 in device %d set to %s\n", ds->n_of_dev,buf);
X res = gpio_store(dev,g_dout2,buf,size);
X if(res<0) return res;
X return size;
}
X
X
static ssize_t din_show(struct device *dev, struct device_attribute *attr, char *buf)
{
X int res;
X struct t_dev_state * ds = dev_get_drvdata(dev);
X res = gpio_show(g_din,buf);
X if(res<0) return res;
X printk(KERN_INFO "atr1 in device %d is equal to %s\n", ds->n_of_dev,buf);
X return res;
}
X
DEVICE_ATTR_WO(dout1);
DEVICE_ATTR_WO(dout2);
DEVICE_ATTR_RO(din);
X
/* List of attributes of our device */
static struct attribute *mydev_attributes[] ={
X & dev_attr_dout1.attr,
X & dev_attr_dout2.attr,
X & dev_attr_din.attr,
X NULL,
};
X
/* Group of attributes of our device */
static struct attribute_group mydev_attrgrp ={
X .attrs = mydev_attributes,
};
X
/* List of groups of attributes of our device */
static const struct attribute_group *mydev_attrgrps[] ={
X &mydev_attrgrp,
X NULL,
};
X
static void my_dev_cleanup(void)
{
X int i;
X printk(KERN_ALERT "MULTI GPIO dev says good bye\n");
X /* deregister the class */
X if(my_dev && my_class) {
X device_destroy(my_class,MKDEV(MAJOR(my_dev),MINOR(my_dev)));
X }
X if(my_cdev) cdev_del(my_cdev);
X my_cdev=NULL;
X /* release device number */
X unregister_chrdev_region(my_dev, 1);
X /* destroy the class */
X if(my_class) {
X class_destroy(my_class);
X my_class=NULL;
X }
X
}
X
struct file_operations fops = {
X .owner = THIS_MODULE,
};
X
X
static int my_dev_create(void)
{
X int res,i;
X printk(KERN_ALERT "Welcome to MULTI GPIO dev\n");
X /* Create the class for our device */
X my_class = class_create(THIS_MODULE, CLASS_NAME);
X if (IS_ERR(my_class)) {
X printk(KERN_ERR "Error creating my_class class.\n");
X res=PTR_ERR(my_class);
X goto err1;
X } /*Get the device number */
X res=alloc_chrdev_region(&my_dev, 0, 1, DEVICE_NAME);
X if(res) {
X printk ("<1>Alocation of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X my_cdev = cdev_alloc();
X if (my_cdev==NULL) {
X printk (KERN_ERR "Allocation of cdev for %s failed\n", DEVICE_NAME);
X res = -ENODEV;
X goto err1;
X }
X my_cdev->ops = &fops;
X my_cdev->owner = THIS_MODULE;
X /* Add device to the system */
X res=cdev_add(my_cdev, my_dev, 1);
X if(res) {
X printk (KERN_ERR "Registration of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X /* Create our device */
X device_create_with_groups(my_class,NULL,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i),&dev_states, mydev_attrgrps, "my_dev%d",MINOR(my_dev));
X printk (KERN_ALERT "Registeration is a success. The major device number %s is %d.\n",
X DEVICE_NAME,
X MAJOR(my_dev));
X return SUCCESS;
err1:
X my_dev_cleanup();
X return res;
}
X
X
void cleanup_tst1( void );
int init_tst1( void );
X
int tst1_remove(struct platform_device *pdev )
{
X if(my_pdev == pdev) {
X if(g_dout1) {
X devm_gpiod_put_array(&pdev->dev, g_dout1);
X }
X if(g_dout2) {
X devm_gpiod_put_array(&pdev->dev, g_dout2);
X }
X if(g_din) {
X devm_gpiod_put_array(&pdev->dev, g_din);
X }
X my_dev_cleanup();
X return 0;
X } else {
X return -ENODEV;
X }
}
X
static int tst1_probe(struct platform_device *pdev)
{
X int res = 0;
X printk(KERN_INFO "MULTI GPIO probe called: %p\n", my_pdev);
X if (my_pdev) {
X //We can't handle more than one device
X printk(KERN_INFO "The driver handles already one device: %p\n", my_pdev);
X return -EINVAL;
X }
X //Now we connect the GPIOs
X //Here we test the GPIO access
X g_dout1 = devm_gpiod_get_array(&pdev->dev, "dout1", GPIOD_OUT_HIGH);
X if(IS_ERR(g_dout1)) {
X res = (int) g_dout1;
X printk (KERN_ERR "I can't connect to the DOUT1 GPIO: error %d\n",res);
X g_dout1 = NULL;
X goto err1;
X };
X g_dout2 = devm_gpiod_get_array(&pdev->dev, "dout2", GPIOD_OUT_HIGH);
X if(IS_ERR(g_dout2)) {
X res = (int) g_dout2;
X printk (KERN_ERR "I can't connect to the DOUT2 GPIO: error %d\n",res);
X g_dout2 = NULL;
X goto err1;
X };
X g_din = devm_gpiod_get_array(&pdev->dev, "din", GPIOD_IN);
X if(IS_ERR(g_din)) {
X res = (int) g_din;
X printk (KERN_ERR "I can't connect to the DIN GPIO: error %d\n",res);
X g_din = NULL;
X goto err1;
X };
X res = my_dev_create();
X if(res<0) return res;
X res = SUCCESS;
X my_pdev = pdev;
X printk(KERN_INFO "KSGPIO probe successfull g_dout1=%d, g_dout2=%d, g_din=%d\n", g_dout1->ndescs, g_dout2->ndescs, g_din->ndescs);
X return res;
X err1:
X tst1_remove(pdev);
X return res;
}
X
//We connect to the platform device
static struct of_device_id multi_gpio_driver_ids[] = {
X {
X .compatible = "wzab,multi-gpio",
X },
X {},
};
X
static struct platform_driver my_driver = {
X .driver = {
X .name = DEVICE_NAME,
X .of_match_table = multi_gpio_driver_ids,
X },
X .probe = tst1_probe,
X .remove = tst1_remove,
};
X
static int tst1_init_module(void)
{
X /* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
X // printk(version);
#endif
X printk(KERN_ALERT "Welcome to MULTI GPIO\n");
X return platform_driver_register(&my_driver);
}
X
X
static void tst1_cleanup_module(void)
{
X printk(KERN_ALERT "MULTI GPIO says good-bye\n");
X platform_driver_unregister(&my_driver);
}
X
//Exported function to check status of the GPIOS
int multi_gpio_check_status(void)
{
X if(my_pdev && g_dout1 && g_dout2 && g_din) return SUCCESS;
X else return -ENODEV;
}
/*
//Exported functions to control GPIOS
int ksgpio_set_start(int val)
{
X if(g_start) {
X gpiod_set_value(g_start,val);
X return SUCCESS;
X } else {
X return -ENODEV;
X }
X
}
X
int ksgpio_set_reset(int val)
{
X if(g_reset) {
X gpiod_set_value(g_reset,val);
X return SUCCESS;
X } else {
X return -ENODEV;
X }
}
*/
EXPORT_SYMBOL_GPL(multi_gpio_check_status);
X
module_init(tst1_init_module);
module_exit(tst1_cleanup_module);
X
SHAR_EOF
(set 20 18 01 25 17 42 00 'multi-gpio.c'
eval "${shar_touch}") && \
chmod 0664 'multi-gpio.c'
if test $? -ne 0
then ${echo} "restore of multi-gpio.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'multi-gpio.c': 'MD5 check failed'
) << \SHAR_EOF
0605477e7ea58cec1481bd13ee2833c1 multi-gpio.c
SHAR_EOF

else
test `LC_ALL=C wc -c < 'multi-gpio.c'` -ne 8127 && \
${echo} "restoration warning: size of 'multi-gpio.c' is not 8127"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0

Wojciech M. Zabołotny

unread,
Jan 25, 2018, 8:08:56 PM1/25/18
to
This are the sources of the device driver, allowing you to create the
group of GPIOs, and access them via sysfs.

I have tested it in a system, where two AXI GPIOs were implemented in the
Xilinx MPSoC based design.
In the device tree, the GPIO groups were defined as follows:
&amba_pl {
multigpio {
compatible = "wzab,multi-gpio";
dout1-gpios = <&axi_gpio_0 0 0>,
<&axi_gpio_0 1 0>,
<&axi_gpio_0 2 0>,
<&axi_gpio_0 3 0>,
<&axi_gpio_0 4 0>,
<&axi_gpio_0 5 0>,
<&axi_gpio_0 6 0>,
<&axi_gpio_0 7 0>;
dout2-gpios = <&axi_gpio_0 0 8>,
<&axi_gpio_0 1 8>,
<&axi_gpio_0 2 8>,
<&axi_gpio_0 3 8>,
<&axi_gpio_0 4 8>,
<&axi_gpio_0 5 8>,
<&axi_gpio_0 6 8>,
<&axi_gpio_0 7 8>;
din-gpios = <&axi_gpio_1 0 0>,
<&axi_gpio_1 1 0>,
<&axi_gpio_1 2 0>,
<&axi_gpio_1 3 0>,
<&axi_gpio_1 4 0>,
<&axi_gpio_1 5 0>,
<&axi_gpio_1 6 0>,
<&axi_gpio_1 7 0>;
};
};

This version of the driver provides simplified creation of the code
handling the groups of GPIOs.

To adjust the list of groups of GPIOs, the user must only define
or modify a single table:

static my_attr_t my_attrs[]={
{"dout1",NULL},
{"dout2",NULL},
{"din",NULL},
{NULL,NULL}
};

Then, after loading the "multi-gpio.ko" module, it is possible to
access GPIOs via shell commands like below:

echo 37 > /sys/class/class_multi_gpio/my_dev0/dout1
cat /sys/class/class_multi_gpio/my_dev0/din
121
echo 17 > /sys/class/class_multi_gpio/my_dev0/dout2

I'm still working on a version, that gets the list of GPIO groups
directly from the DT.

Please note, that this is an experimental code. If you decide to use it,
you do it on your own risk.
Please note, that the code does not change the direction of GPIOs.
In my design I have decided GPIOs as "all outputs" or "all inputs" in the
HDL design.
Of course you may modify the my_attr_t type so that it includes also the direction
and change the initialization routines appropriately.

Good luck!
Wojtek

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh05378
# Made on 2018-01-26 02:00 CET by <wzab@wzab>.
# Source directory was '/tmp/yy'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 7929 -rw-rw-r-- multi-gpio.c
//Here we define the attributes together with their access
typedef struct {
X const char * name;
X struct gpio_descs * gdescs;
X struct device_attribute attr;
} my_attr_t;
X
static my_attr_t my_attrs[]={
X {"dout1",NULL},
X {"dout2",NULL},
X {"din",NULL},
X {NULL,NULL}
};
X
static struct t_dev_state {
X int n_of_dev;
} dev_states;
X
//It is a dirty trick, but we can service only one device :-(
static struct platform_device * my_pdev = NULL;
static dev_t my_dev=0;
static struct cdev *my_cdev = NULL;
static struct class *my_class = NULL;
X
static struct gpio_descs * find_gds(struct device_attribute *attr)
{
X struct gpio_descs * gds = NULL;
X my_attr_t * mattr = &my_attrs[0];
X while(mattr->name) {
X if(!strcmp(mattr->name,attr->attr.name)) {
X gds = mattr->gdescs;
X break;
X }
X mattr++;
X }
X return gds;
}
X
//Store result buffer to gpio
static ssize_t gpio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
X long val;
X int res;
X int i;
X struct gpio_descs * gds = NULL;
X long mask = 1;
X printk(KERN_INFO "Writing attribute %s : %s\n", attr->attr.name, buf);
X //Find the matching attribute
X gds = find_gds(attr);
X if(gds==NULL) return -ENODEV;
X res=kstrtol(buf, 0, &val);
X if(res<0) return res;
X for(i=0;i<gds->ndescs;i++) {
X gpiod_set_value(gds->desc[i],(val & mask) ? 1 : 0);
X mask <<= 1;
X }
X return size;
}
X
//Show the state of the gpio
static ssize_t gpio_show(struct device *dev, struct device_attribute *attr, char *buf)
{
X long val=0;
X int res;
X int i;
X struct gpio_descs * gds = NULL;
X long mask = 1;
X //Find the matching attribute
X gds = find_gds(attr);
X if(gds==NULL) return -ENODEV;
X for(i=0;i<gds->ndescs;i++) {
X res=gpiod_get_value(gds->desc[i]);
X if(res<0) return res;
X if(res) val |= mask;
X mask <<= 1;
X }
X res=snprintf(buf,PAGE_SIZE,"%ld",val);
X printk(KERN_INFO "Reading attribute %s : %s\n", attr->attr.name, buf);
X return res;
X my_attr_t * mattr = &my_attrs[0];
X struct device * dev = NULL;
X dev = device_create(my_class,NULL,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i),&dev_states, "my_dev%d",MINOR(my_dev));
X if(IS_ERR(dev)) {
X res = (int) dev;
X printk (KERN_ERR "I can't create device %s: error %d\n",DEVICE_NAME,res);
X goto err1;
X };
X /* Create device files for attributes */
X while(mattr->name) {
X //Below I reconstruct the behavior of __ATTR macro
X //I don't know if it will remain stable in next kernel versions though...
X mattr->attr.attr.name = mattr->name;
X mattr->attr.attr.mode=(S_IWUSR | S_IRUGO);
X mattr->attr.show = gpio_show;
X mattr->attr.store = gpio_store;
X res = device_create_file(dev,&mattr->attr);
X if(res) {
X printk (KERN_ERR "Creating file for attribute %s failed\n",
X mattr->name);
X goto err1;
X }
X mattr++;
X }
X printk (KERN_ALERT "Registeration is a success. The major device number %s is %d.\n",
X DEVICE_NAME,
X MAJOR(my_dev));
X return SUCCESS;
err1:
X my_dev_cleanup();
X return res;
}
X
X
void cleanup_tst1( void );
int init_tst1( void );
X
int tst1_remove(struct platform_device *pdev )
{
X if(my_pdev == pdev) {
X my_attr_t * mattr=&my_attrs[0];
X while(mattr->name) {
X devm_gpiod_put_array(&pdev->dev, mattr->gdescs);
X mattr->gdescs = NULL;
X mattr++;
X }
X my_dev_cleanup();
X return 0;
X } else {
X return -ENODEV;
X }
}
X
static int tst1_probe(struct platform_device *pdev)
{
X int res = 0;
X my_attr_t * mattr = &my_attrs[0];
X printk(KERN_INFO "MULTI GPIO probe called: %p\n", my_pdev);
X if (my_pdev) {
X //We can't handle more than one device
X printk(KERN_INFO "The driver handles already one device: %p\n", my_pdev);
X return -EINVAL;
X }
X //Now we connect the GPIOs
X while(mattr->name) {
X struct gpio_descs * gds = devm_gpiod_get_array(&pdev->dev, mattr->name, GPIOD_ASIS);
X if(IS_ERR(gds)) {
X res = (int) gds;
X printk (KERN_ERR "I can't connect to the GPIO group %s: error %d\n",mattr->name,res);
X goto err1;
X };
X mattr->gdescs = gds;
X mattr++;
X }
X res = my_dev_create();
X if(res<0) return res;
X res = SUCCESS;
X my_pdev = pdev;
X printk(KERN_INFO "MULTI GPIO probe successfull\n");
/*
X
//Exported function to check status of the GPIOS
int multi_gpio_check_status(void)
{
X if(my_pdev && g_dout1 && g_dout2 && g_din) return SUCCESS;
X else return -ENODEV;
}
//Exported functions to control GPIOS
int ksgpio_set_start(int val)
{
X if(g_start) {
X gpiod_set_value(g_start,val);
X return SUCCESS;
X } else {
X return -ENODEV;
X }
X
}
X
int ksgpio_set_reset(int val)
{
X if(g_reset) {
X gpiod_set_value(g_reset,val);
X return SUCCESS;
X } else {
X return -ENODEV;
X }
}
EXPORT_SYMBOL_GPL(multi_gpio_check_status);
*/
X
module_init(tst1_init_module);
module_exit(tst1_cleanup_module);
X
SHAR_EOF
(set 20 18 01 26 01 45 00 'multi-gpio.c'
eval "${shar_touch}") && \
chmod 0664 'multi-gpio.c'
if test $? -ne 0
then ${echo} "restore of multi-gpio.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'multi-gpio.c': 'MD5 check failed'
) << \SHAR_EOF
75114ec2a75c75a964db66454f6674a0 multi-gpio.c
SHAR_EOF

else
test `LC_ALL=C wc -c < 'multi-gpio.c'` -ne 7929 && \
${echo} "restoration warning: size of 'multi-gpio.c' is not 7929"

wza...@gmail.com

unread,
Jan 28, 2018, 9:32:47 AM1/28/18
to
You may modify the driver to define also the direction of your GPIO group:

//Here we define the attributes together with their access
typedef struct {
const char * name;
enum gpiod_flags flags;
struct gpio_descs * gdescs;
struct device_attribute attr;
} my_attr_t;

static my_attr_t my_attrs[]={
{"dout1",GPIOD_OUT_HIGH,NULL},
{"dout2",GPIOD_OUT_HIGH,NULL},
{"din",GPIOD_IN,NULL},
{NULL,GPIOD_ASIS,NULL}
};

[...]

static int tst1_probe(struct platform_device *pdev)
{
int res = 0;
my_attr_t * mattr = &my_attrs[0];
printk(KERN_INFO "MULTI GPIO probe called: %p\n", my_pdev);
if (my_pdev) {
//We can't handle more than one device
printk(KERN_INFO "The driver handles already one device: %p\n", my_pdev);
return -EINVAL;
}
//Now we connect the GPIOs
while(mattr->name) {
struct gpio_descs * gds = devm_gpiod_get_array(&pdev->dev, mattr->name, mattr->flags);
if(IS_ERR(gds)) {
res = (int) gds;
printk (KERN_ERR "I can't connect to the GPIO group %s: error %d\n",mattr->name,res);
goto err1;
};
mattr->gdescs = gds;
mattr++;
}
res = my_dev_create();
if(res<0) return res;
res = SUCCESS;
my_pdev = pdev;
printk(KERN_INFO "MULTI GPIO probe successfull\n");
return res;
err1:
tst1_remove(pdev);
return res;
}
0 new messages