I am using the processor of Allwinner A40i. The kernel version is 3.10, an external STM32, STM32 generates a IO interrupt per 8ms, and the A40i obtains the interrupt signal (rising edge) through the GPIO. There is no other component in the middle. I found that occasion occasionally there will I got multiple interruptions in 8ms, but when I used the oscilloscope to grab the waveforms, the waveforms were normal.
a apart of device tree:
spiio{
compatible = "dobot, spiio";
spiio_gpio = <&pio PI 10 6 default default default>; /*PI 10, 0->input/6->EINT, 1->level, 2->down pull, 1->data*/
clocks = <&clk_pio>;
};
spiio.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h>
#include <linux/major.h>
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/pinctrl/pinconf-sunxi.h>
static int MajorDevNum = 0;
static int SpiioNum = 0;
static int IrqNum = 0;
static struct class *SpiioClass;
static int IrqOccurred = 0;
static wait_queue_head_t WaitQueue;
static spinlock_t RWLock;
static void SetIrqOccurred(int newIrqOccurred)
{
spin_lock_irq(&RWLock);
IrqOccurred = newIrqOccurred;
spin_unlock_irq(&RWLock);
}
static irqreturn_t spiio_irq_handler(int irq, void *dev_id)
{
// pr_debug("spiio irq ocurred on IRQ %d\n", irq);
if (irq == IrqNum) {
SetIrqOccurred(1);
wake_up_interruptible(&WaitQueue);
}
return IRQ_HANDLED;
}
static int spiio_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
// pr_info("start read\n");
#if 1
int ret = 0;
// pr_info("this is read. IrqOccurred = %d\n", IrqOccurred);
// ret = wait_event_interruptible(WaitQueue, IrqOccurred);
ret = wait_event_interruptible_timeout(WaitQueue, IrqOccurred, msecs_to_jiffies(10));
pr_info("wait end-timeout, ret = %d, IrqOccurred = %d\n", ret, IrqOccurred);
if (IrqOccurred) SetIrqOccurred(0);
if (ret > 0) {
return 1;
} else if (ret == 0){
return 0; //timeout
} else {
pr_err("wait_event_intrruptible_timeout return %d\n", ret);
return -1;
}
#endif
}
/* write(fd, &val, 1); */
static int spiio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
return -1;
}
static int spiio_drv_open(struct inode *node, struct file *file)
{
int err = 0;
pr_info("this is open\n");
#if 0
spin_lock_init(&RWLock);
init_waitqueue_head(&WaitQueue);
IrqNum = gpio_to_irq(SpiioNum);
if (IS_ERR(IrqNum)) {
pr_err("irqNum is err\n");
free_irq(IrqNum, NULL);
return -1;
}
//if ((err = request_irq(IrqNum, spiio_irq_handler, IRQF_SHARED | IRQF_TRIGGER_RISING, "spiio_irq", &pdev->dev)) < 0)
if ((err = request_irq(IrqNum, spiio_irq_handler, IRQF_TRIGGER_RISING, "spiio_irq", NULL)) < 0)
{
pr_err("requst_irq failed, err = %d\n", err);
free_irq(IrqNum, NULL);
return -1;
}
pr_info("add irq %d on pin %d success.\n", IrqNum, SpiioNum);
#endif
return 0;
}
static int spiio_drv_close(struct inode *node, struct file *file)
{
#if 0
free_irq(IrqNum, NULL);
#endif
return 0;
}
static long spiio_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
//static unsigned int spiio_drv_poll(struct file *file, struct poll_table_struct *wait)
static unsigned int spiio_drv_poll(struct file *file, struct poll_table *wait)
{
#if 0
// pr_info("this is poll.\n");
int ret = 0;
poll_wait(file, &WaitQueue, wait);
if (IrqOccurred)
{
mutex_lock(&RWLock);
IrqOccurred = 0; //need lock
mutex_unlock(&RWLock);
// pr_debug(" an irq occurred. return %d\n", POLLIN);
return POLLIN;
} else {
// pr_debug("no irq occurred, IrqOccurred = %d\n", IrqOccurred);
return 0;
}
#endif
#if 0
if (irq_set_affinity_hint(irqNum, cpumask_of(1)) < 0) {
pr_info("failed to set affinity\n");
}
#endif
return 0;
}
static struct file_operations spiio_drv = {
.owner = THIS_MODULE,
.open = spiio_drv_open,
.read = spiio_drv_read,
.write = spiio_drv_write,
.release = spiio_drv_close,
.unlocked_ioctl = spiio_drv_ioctl,
.poll = spiio_drv_poll,
};
int spiio_probe(struct platform_device *pdev)
{
int err = 0;
struct gpio_config pinConfig;
char pinName[32] = {0};
unsigned int config = 0;
struct device_node *nd = pdev->dev.of_node;
if (!nd) {
pr_err("no found device tree node\n");
return -1;
}
if ((of_gpio_named_count(nd, "spiio_gpio") <= 0))
{
pr_err("no found spiio_gpio node\n");
return -1;
}
SpiioNum = of_get_named_gpio_flags(nd, "spiio_gpio", 0, (enum of_gpio_flags *)&pinConfig);
if (!gpio_is_valid(SpiioNum))
{
pr_err("gpio isn't valid\n");
return -1;
}
if (gpio_request(SpiioNum, pdev->name) < 0)
{
pr_err("gpio request failed, GPIO:%d\n", SpiioNum);
gpio_free(SpiioNum);
return -1;
}
sunxi_gpio_to_name(pinConfig.gpio, pinName);
pr_info("pinName = %s\n", pinName);
pr_info("index = %d\n", pinConfig.gpio);
pr_info("mul_sel = %d\n", pinConfig.mul_sel);
pr_info("pull = %d\n", pinConfig.pull);
pr_info("drv_level = %d\n", pinConfig.drv_level);
pr_info("data = %d\n", pinConfig.data);
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, pinConfig.mul_sel);
pin_config_set(SUNXI_PINCTRL, pinName, config);
if (pinConfig.pull != GPIO_PULL_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pinConfig.pull);
pin_config_set(SUNXI_PINCTRL, pinName, config);
pr_info("set pull:%d\n", pinConfig.pull);
}
if (pinConfig.drv_level != GPIO_DRVLVL_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, pinConfig.drv_level);
pin_config_set(SUNXI_PINCTRL, pinName, config);
pr_info("set drv_level:%d\n", pinConfig.drv_level);
}
if (pinConfig.data != GPIO_DATA_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, pinConfig.data);
pin_config_set(SUNXI_PINCTRL, pinName, config);
pr_info("set data:%d\n", pinConfig.data);
}
if (gpio_direction_input(SpiioNum) < 0)
{
pr_err("gpio_direction_input failed %d\n", SpiioNum);
gpio_free(SpiioNum);
return -1;
}
MajorDevNum = register_chrdev(0, "spiio", &spiio_drv); /* /dev/spiio */
if (MajorDevNum < 0)
{
pr_err("failed to get major device number\n");
gpio_free(SpiioNum);
return -1;
}
SpiioClass = class_create(THIS_MODULE, "spiio_class");
if (IS_ERR(SpiioClass))
{
pr_err("spiio class has an error\n");
unregister_chrdev(MajorDevNum, "spiio");
gpio_free(SpiioNum);
return PTR_ERR(SpiioClass);
}
device_create(SpiioClass, NULL, MKDEV(MajorDevNum, 0), NULL, "spiio%d", 0); /* /dev/100ask_spiio0 */
pr_info("gpio is ok, spiio num is %d\n", SpiioNum);
#if 1
spin_lock_init(&RWLock);
init_waitqueue_head(&WaitQueue);
IrqNum = gpio_to_irq(SpiioNum);
if (IS_ERR(IrqNum)) {
pr_err("irqNum is err\n");
free_irq(IrqNum, NULL);
gpio_free(SpiioNum);
unregister_chrdev(MajorDevNum, "spiio");
return -1;
}
//if ((err = request_irq(IrqNum, spiio_irq_handler, IRQF_SHARED | IRQF_TRIGGER_RISING, "spiio_irq", &pdev->dev)) < 0)
if ((err = request_irq(IrqNum, spiio_irq_handler, IRQF_TRIGGER_RISING, "spiio_irq", NULL)) < 0)
{
pr_err("requst_irq failed, err = %d\n", err);
free_irq(IrqNum, NULL);
gpio_free(SpiioNum);
unregister_chrdev(MajorDevNum, "spiio");
return -1;
}
pr_info("add irq %d on pin %d success.\n", IrqNum, SpiioNum);
#endif
#if 0
if (irq_set_affinity_hint(irqNum, cpumask_of(1)) < 0) {
pr_info("failed to set affinity\n");
}
#endif
return 0;
}
int spiio_remove(struct platform_device *pdev)
{
#if 1
free_irq(IrqNum, NULL);
#endif
device_destroy(SpiioClass, MKDEV(MajorDevNum, 0));
class_destroy(SpiioClass);
unregister_chrdev(MajorDevNum, "spiio");
gpio_free(SpiioNum);
pr_info("gpio remove ...\n");
return 0;
}
struct of_device_id ids[] = {
{.compatible = "dobot, spiio"},
{},
};
static struct platform_driver chip_demo_gpio_driver = {
.probe = spiio_probe,
.remove = spiio_remove,
/* .shutdown = spiio_remove,*/
.driver = {
.name = "spiio",
.of_match_table = ids,
},
};
static int __init spiio_init(void)
{
int err;
err = platform_driver_register(&chip_demo_gpio_driver);
return err;
}
static void __exit spiio_exit(void)
{
platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(spiio_init);
module_exit(spiio_exit);
MODULE_LICENSE("GPL");
a part of dmesg:
[ 6568.744425] this is open
[ 6568.745230] wait end-timeout, ret = 10, IrqOccurred = 1
[ 6568.746052] wait end-timeout, ret = 9, IrqOccurred = 1
This is just one of the abnormal kernel printing. Through the kernel printing, two interruptions have been obtained in GPIO Controller. What is the reason for this?