Skip to content

Commit 6a37454

Browse files
qizhangzsjshweta
authored andcommitted
spidev: support poll to wait interrupt from SPI controller
Add epoll support for SPI devices transfers based on the per SPI device interrupt mechanism provided by the Virtio SPI controller. Tracked-On: OAM-131278 Signed-off-by: Qi Zhang <qi1.zhang@intel.com>
1 parent b937c7c commit 6a37454

1 file changed

Lines changed: 82 additions & 1 deletion

File tree

drivers/spi/spidev.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626

2727
#include <linux/uaccess.h>
2828

29+
#include <linux/irq.h>
30+
#include <linux/interrupt.h>
31+
#include <linux/poll.h>
32+
#include <linux/irqdomain.h>
2933

3034
/*
3135
* This supports access to SPI devices using normal userspace I/O calls.
@@ -79,6 +83,10 @@ struct spidev_data {
7983
u8 *tx_buffer;
8084
u8 *rx_buffer;
8185
u32 speed_hz;
86+
int irq;
87+
bool notified;
88+
struct wait_queue_head waitq;
89+
spinlock_t irq_lock;
8290
};
8391

8492
static LIST_HEAD(device_list);
@@ -90,6 +98,43 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
9098

9199
/*-------------------------------------------------------------------------*/
92100

101+
static irqreturn_t handshake_irq(int __attribute__((unused)) irq, void *id)
102+
{
103+
struct spidev_data *spidev = id;
104+
unsigned long flags;
105+
106+
spin_lock_irqsave(&spidev->irq_lock, flags);
107+
spidev->notified = true;
108+
spin_unlock_irqrestore(&spidev->irq_lock, flags);
109+
wake_up_interruptible(&spidev->waitq);
110+
111+
return IRQ_HANDLED;
112+
}
113+
114+
static int spidev_irq_get(struct spi_device *spi)
115+
{
116+
struct irq_fwspec fwspec;
117+
struct irq_domain *domain;
118+
struct spi_controller *ctlr = spi->controller;
119+
int irq = -EINVAL;
120+
121+
fwspec.fwnode = dev_fwnode(ctlr->dev.parent);
122+
fwspec.param[0] = spi_get_chipselect(spi, 0);
123+
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
124+
fwspec.param_count = 2;
125+
126+
domain = irq_find_matching_fwnode(fwspec.fwnode, DOMAIN_BUS_ANY);
127+
if (!domain)
128+
return -EINVAL;
129+
dev_info(&spi->dev, "found domain: %s\n", domain->name);
130+
131+
irq = irq_create_fwspec_mapping(&fwspec);
132+
if (irq <= 0)
133+
return -EINVAL;
134+
135+
return irq;
136+
}
137+
93138
static ssize_t
94139
spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message)
95140
{
@@ -673,6 +718,22 @@ static int spidev_release(struct inode *inode, struct file *filp)
673718
return 0;
674719
}
675720

721+
static unsigned int spidev_poll(struct file *filp, struct poll_table_struct *wait)
722+
{
723+
struct spidev_data *spidev;
724+
__poll_t mask = 0;
725+
726+
spidev = filp->private_data;
727+
poll_wait(filp, &spidev->waitq, wait);
728+
if (spidev->notified) {
729+
mask |= ( POLLIN | POLLRDNORM );
730+
spin_lock_irq(&spidev->irq_lock);
731+
spidev->notified = false;
732+
spin_unlock_irq(&spidev->irq_lock);
733+
}
734+
return mask;
735+
}
736+
676737
static const struct file_operations spidev_fops = {
677738
.owner = THIS_MODULE,
678739
/* REVISIT switch to aio primitives, so that userspace
@@ -684,6 +745,7 @@ static const struct file_operations spidev_fops = {
684745
.unlocked_ioctl = spidev_ioctl,
685746
.compat_ioctl = spidev_compat_ioctl,
686747
.open = spidev_open,
748+
.poll = spidev_poll,
687749
.release = spidev_release,
688750
};
689751

@@ -772,7 +834,7 @@ static int spidev_probe(struct spi_device *spi)
772834
{
773835
int (*match)(struct device *dev);
774836
struct spidev_data *spidev;
775-
int status;
837+
int status, irq;
776838
unsigned long minor;
777839

778840
match = device_get_match_data(&spi->dev);
@@ -791,6 +853,7 @@ static int spidev_probe(struct spi_device *spi)
791853
spidev->spi = spi;
792854
mutex_init(&spidev->spi_lock);
793855
mutex_init(&spidev->buf_lock);
856+
spin_lock_init(&spidev->irq_lock);
794857

795858
INIT_LIST_HEAD(&spidev->device_entry);
796859

@@ -819,6 +882,24 @@ static int spidev_probe(struct spi_device *spi)
819882

820883
spidev->speed_hz = spi->max_speed_hz;
821884

885+
init_waitqueue_head(&spidev->waitq);
886+
//ACPI_GENERIC_GSI is NOT supported on x86 !?
887+
//irq = fwnode_irq_get(dev_fwnode(&spi->dev), 0);
888+
irq = spidev_irq_get(spi);
889+
if (irq < 0) {
890+
dev_info(&spi->dev, "fail to get device irq %d\n", irq);
891+
} else {
892+
dev_dbg(&spi->dev, "got mapped irq %d\n", irq);
893+
status = request_irq(irq, handshake_irq,
894+
IRQF_TRIGGER_RISING, dev_name(&spi->dev),
895+
spidev);
896+
if (status) {
897+
dev_dbg(&spi->dev, "unable to request irq %d\n", irq);
898+
status = 0;
899+
} else
900+
spidev->irq = irq;
901+
}
902+
822903
if (status == 0)
823904
spi_set_drvdata(spi, spidev);
824905
else

0 commit comments

Comments
 (0)