162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GPIO driver for virtio-based virtual GPIO controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 metux IT consult
662306a36Sopenharmony_ci * Enrico Weigelt, metux IT consult <info@metux.net>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2021 Linaro.
962306a36Sopenharmony_ci * Viresh Kumar <viresh.kumar@linaro.org>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/completion.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <linux/virtio_config.h>
2162306a36Sopenharmony_ci#include <uapi/linux/virtio_gpio.h>
2262306a36Sopenharmony_ci#include <uapi/linux/virtio_ids.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct virtio_gpio_line {
2562306a36Sopenharmony_ci	struct mutex lock; /* Protects line operation */
2662306a36Sopenharmony_ci	struct completion completion;
2762306a36Sopenharmony_ci	struct virtio_gpio_request req ____cacheline_aligned;
2862306a36Sopenharmony_ci	struct virtio_gpio_response res ____cacheline_aligned;
2962306a36Sopenharmony_ci	unsigned int rxlen;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct vgpio_irq_line {
3362306a36Sopenharmony_ci	u8 type;
3462306a36Sopenharmony_ci	bool disabled;
3562306a36Sopenharmony_ci	bool masked;
3662306a36Sopenharmony_ci	bool queued;
3762306a36Sopenharmony_ci	bool update_pending;
3862306a36Sopenharmony_ci	bool queue_pending;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	struct virtio_gpio_irq_request ireq ____cacheline_aligned;
4162306a36Sopenharmony_ci	struct virtio_gpio_irq_response ires ____cacheline_aligned;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct virtio_gpio {
4562306a36Sopenharmony_ci	struct virtio_device *vdev;
4662306a36Sopenharmony_ci	struct mutex lock; /* Protects virtqueue operation */
4762306a36Sopenharmony_ci	struct gpio_chip gc;
4862306a36Sopenharmony_ci	struct virtio_gpio_line *lines;
4962306a36Sopenharmony_ci	struct virtqueue *request_vq;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* irq support */
5262306a36Sopenharmony_ci	struct virtqueue *event_vq;
5362306a36Sopenharmony_ci	struct mutex irq_lock; /* Protects irq operation */
5462306a36Sopenharmony_ci	raw_spinlock_t eventq_lock; /* Protects queuing of the buffer */
5562306a36Sopenharmony_ci	struct vgpio_irq_line *irq_lines;
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int _virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
5962306a36Sopenharmony_ci			    u8 txvalue, u8 *rxvalue, void *response, u32 rxlen)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct virtio_gpio_line *line = &vgpio->lines[gpio];
6262306a36Sopenharmony_ci	struct virtio_gpio_request *req = &line->req;
6362306a36Sopenharmony_ci	struct virtio_gpio_response *res = response;
6462306a36Sopenharmony_ci	struct scatterlist *sgs[2], req_sg, res_sg;
6562306a36Sopenharmony_ci	struct device *dev = &vgpio->vdev->dev;
6662306a36Sopenharmony_ci	int ret;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/*
6962306a36Sopenharmony_ci	 * Prevent concurrent requests for the same line since we have
7062306a36Sopenharmony_ci	 * pre-allocated request/response buffers for each GPIO line. Moreover
7162306a36Sopenharmony_ci	 * Linux always accesses a GPIO line sequentially, so this locking shall
7262306a36Sopenharmony_ci	 * always go through without any delays.
7362306a36Sopenharmony_ci	 */
7462306a36Sopenharmony_ci	mutex_lock(&line->lock);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	req->type = cpu_to_le16(type);
7762306a36Sopenharmony_ci	req->gpio = cpu_to_le16(gpio);
7862306a36Sopenharmony_ci	req->value = cpu_to_le32(txvalue);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	sg_init_one(&req_sg, req, sizeof(*req));
8162306a36Sopenharmony_ci	sg_init_one(&res_sg, res, rxlen);
8262306a36Sopenharmony_ci	sgs[0] = &req_sg;
8362306a36Sopenharmony_ci	sgs[1] = &res_sg;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	line->rxlen = 0;
8662306a36Sopenharmony_ci	reinit_completion(&line->completion);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * Virtqueue callers need to ensure they don't call its APIs with other
9062306a36Sopenharmony_ci	 * virtqueue operations at the same time.
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	mutex_lock(&vgpio->lock);
9362306a36Sopenharmony_ci	ret = virtqueue_add_sgs(vgpio->request_vq, sgs, 1, 1, line, GFP_KERNEL);
9462306a36Sopenharmony_ci	if (ret) {
9562306a36Sopenharmony_ci		dev_err(dev, "failed to add request to vq\n");
9662306a36Sopenharmony_ci		mutex_unlock(&vgpio->lock);
9762306a36Sopenharmony_ci		goto out;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	virtqueue_kick(vgpio->request_vq);
10162306a36Sopenharmony_ci	mutex_unlock(&vgpio->lock);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	wait_for_completion(&line->completion);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (unlikely(res->status != VIRTIO_GPIO_STATUS_OK)) {
10662306a36Sopenharmony_ci		dev_err(dev, "GPIO request failed: %d\n", gpio);
10762306a36Sopenharmony_ci		ret = -EINVAL;
10862306a36Sopenharmony_ci		goto out;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (unlikely(line->rxlen != rxlen)) {
11262306a36Sopenharmony_ci		dev_err(dev, "GPIO operation returned incorrect len (%u : %u)\n",
11362306a36Sopenharmony_ci			rxlen, line->rxlen);
11462306a36Sopenharmony_ci		ret = -EINVAL;
11562306a36Sopenharmony_ci		goto out;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (rxvalue)
11962306a36Sopenharmony_ci		*rxvalue = res->value;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciout:
12262306a36Sopenharmony_ci	mutex_unlock(&line->lock);
12362306a36Sopenharmony_ci	return ret;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
12762306a36Sopenharmony_ci			   u8 txvalue, u8 *rxvalue)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct virtio_gpio_line *line = &vgpio->lines[gpio];
13062306a36Sopenharmony_ci	struct virtio_gpio_response *res = &line->res;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return _virtio_gpio_req(vgpio, type, gpio, txvalue, rxvalue, res,
13362306a36Sopenharmony_ci				sizeof(*res));
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void virtio_gpio_free(struct gpio_chip *gc, unsigned int gpio)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
14162306a36Sopenharmony_ci			VIRTIO_GPIO_DIRECTION_NONE, NULL);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int virtio_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
14762306a36Sopenharmony_ci	u8 direction;
14862306a36Sopenharmony_ci	int ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_DIRECTION, gpio, 0,
15162306a36Sopenharmony_ci			      &direction);
15262306a36Sopenharmony_ci	if (ret)
15362306a36Sopenharmony_ci		return ret;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	switch (direction) {
15662306a36Sopenharmony_ci	case VIRTIO_GPIO_DIRECTION_IN:
15762306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_IN;
15862306a36Sopenharmony_ci	case VIRTIO_GPIO_DIRECTION_OUT:
15962306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_OUT;
16062306a36Sopenharmony_ci	default:
16162306a36Sopenharmony_ci		return -EINVAL;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int virtio_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
17062306a36Sopenharmony_ci			       VIRTIO_GPIO_DIRECTION_IN, NULL);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int virtio_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
17462306a36Sopenharmony_ci					int value)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
17762306a36Sopenharmony_ci	int ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_VALUE, gpio, value, NULL);
18062306a36Sopenharmony_ci	if (ret)
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
18462306a36Sopenharmony_ci			       VIRTIO_GPIO_DIRECTION_OUT, NULL);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int virtio_gpio_get(struct gpio_chip *gc, unsigned int gpio)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
19062306a36Sopenharmony_ci	u8 value;
19162306a36Sopenharmony_ci	int ret;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_VALUE, gpio, 0, &value);
19462306a36Sopenharmony_ci	return ret ? ret : value;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void virtio_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_VALUE, gpio, value, NULL);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* Interrupt handling */
20562306a36Sopenharmony_cistatic void virtio_gpio_irq_prepare(struct virtio_gpio *vgpio, u16 gpio)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[gpio];
20862306a36Sopenharmony_ci	struct virtio_gpio_irq_request *ireq = &irq_line->ireq;
20962306a36Sopenharmony_ci	struct virtio_gpio_irq_response *ires = &irq_line->ires;
21062306a36Sopenharmony_ci	struct scatterlist *sgs[2], req_sg, res_sg;
21162306a36Sopenharmony_ci	int ret;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (WARN_ON(irq_line->queued || irq_line->masked || irq_line->disabled))
21462306a36Sopenharmony_ci		return;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ireq->gpio = cpu_to_le16(gpio);
21762306a36Sopenharmony_ci	sg_init_one(&req_sg, ireq, sizeof(*ireq));
21862306a36Sopenharmony_ci	sg_init_one(&res_sg, ires, sizeof(*ires));
21962306a36Sopenharmony_ci	sgs[0] = &req_sg;
22062306a36Sopenharmony_ci	sgs[1] = &res_sg;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ret = virtqueue_add_sgs(vgpio->event_vq, sgs, 1, 1, irq_line, GFP_ATOMIC);
22362306a36Sopenharmony_ci	if (ret) {
22462306a36Sopenharmony_ci		dev_err(&vgpio->vdev->dev, "failed to add request to eventq\n");
22562306a36Sopenharmony_ci		return;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	irq_line->queued = true;
22962306a36Sopenharmony_ci	virtqueue_kick(vgpio->event_vq);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void virtio_gpio_irq_enable(struct irq_data *d)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
23562306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
23662306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	raw_spin_lock(&vgpio->eventq_lock);
23962306a36Sopenharmony_ci	irq_line->disabled = false;
24062306a36Sopenharmony_ci	irq_line->masked = false;
24162306a36Sopenharmony_ci	irq_line->queue_pending = true;
24262306a36Sopenharmony_ci	raw_spin_unlock(&vgpio->eventq_lock);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	irq_line->update_pending = true;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void virtio_gpio_irq_disable(struct irq_data *d)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
25062306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
25162306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	raw_spin_lock(&vgpio->eventq_lock);
25462306a36Sopenharmony_ci	irq_line->disabled = true;
25562306a36Sopenharmony_ci	irq_line->masked = true;
25662306a36Sopenharmony_ci	irq_line->queue_pending = false;
25762306a36Sopenharmony_ci	raw_spin_unlock(&vgpio->eventq_lock);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	irq_line->update_pending = true;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void virtio_gpio_irq_mask(struct irq_data *d)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
26562306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
26662306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	raw_spin_lock(&vgpio->eventq_lock);
26962306a36Sopenharmony_ci	irq_line->masked = true;
27062306a36Sopenharmony_ci	raw_spin_unlock(&vgpio->eventq_lock);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic void virtio_gpio_irq_unmask(struct irq_data *d)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
27662306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
27762306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	raw_spin_lock(&vgpio->eventq_lock);
28062306a36Sopenharmony_ci	irq_line->masked = false;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Queue the buffer unconditionally on unmask */
28362306a36Sopenharmony_ci	virtio_gpio_irq_prepare(vgpio, d->hwirq);
28462306a36Sopenharmony_ci	raw_spin_unlock(&vgpio->eventq_lock);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int virtio_gpio_irq_set_type(struct irq_data *d, unsigned int type)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
29062306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
29162306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	switch (type) {
29462306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
29562306a36Sopenharmony_ci		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
29862306a36Sopenharmony_ci		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING;
29962306a36Sopenharmony_ci		break;
30062306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
30162306a36Sopenharmony_ci		type = VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
30462306a36Sopenharmony_ci		type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW;
30562306a36Sopenharmony_ci		break;
30662306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
30762306a36Sopenharmony_ci		type = VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH;
30862306a36Sopenharmony_ci		break;
30962306a36Sopenharmony_ci	default:
31062306a36Sopenharmony_ci		dev_err(&vgpio->vdev->dev, "unsupported irq type: %u\n", type);
31162306a36Sopenharmony_ci		return -EINVAL;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	irq_line->type = type;
31562306a36Sopenharmony_ci	irq_line->update_pending = true;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic void virtio_gpio_irq_bus_lock(struct irq_data *d)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
32362306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	mutex_lock(&vgpio->irq_lock);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void virtio_gpio_irq_bus_sync_unlock(struct irq_data *d)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
33162306a36Sopenharmony_ci	struct virtio_gpio *vgpio = gpiochip_get_data(gc);
33262306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line = &vgpio->irq_lines[d->hwirq];
33362306a36Sopenharmony_ci	u8 type = irq_line->disabled ? VIRTIO_GPIO_IRQ_TYPE_NONE : irq_line->type;
33462306a36Sopenharmony_ci	unsigned long flags;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (irq_line->update_pending) {
33762306a36Sopenharmony_ci		irq_line->update_pending = false;
33862306a36Sopenharmony_ci		virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_IRQ_TYPE, d->hwirq, type,
33962306a36Sopenharmony_ci				NULL);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		/* Queue the buffer only after interrupt is enabled */
34262306a36Sopenharmony_ci		raw_spin_lock_irqsave(&vgpio->eventq_lock, flags);
34362306a36Sopenharmony_ci		if (irq_line->queue_pending) {
34462306a36Sopenharmony_ci			irq_line->queue_pending = false;
34562306a36Sopenharmony_ci			virtio_gpio_irq_prepare(vgpio, d->hwirq);
34662306a36Sopenharmony_ci		}
34762306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&vgpio->eventq_lock, flags);
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	mutex_unlock(&vgpio->irq_lock);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic struct irq_chip vgpio_irq_chip = {
35462306a36Sopenharmony_ci	.name			= "virtio-gpio",
35562306a36Sopenharmony_ci	.irq_enable		= virtio_gpio_irq_enable,
35662306a36Sopenharmony_ci	.irq_disable		= virtio_gpio_irq_disable,
35762306a36Sopenharmony_ci	.irq_mask		= virtio_gpio_irq_mask,
35862306a36Sopenharmony_ci	.irq_unmask		= virtio_gpio_irq_unmask,
35962306a36Sopenharmony_ci	.irq_set_type		= virtio_gpio_irq_set_type,
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* These are required to implement irqchip for slow busses */
36262306a36Sopenharmony_ci	.irq_bus_lock		= virtio_gpio_irq_bus_lock,
36362306a36Sopenharmony_ci	.irq_bus_sync_unlock	= virtio_gpio_irq_bus_sync_unlock,
36462306a36Sopenharmony_ci};
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic bool ignore_irq(struct virtio_gpio *vgpio, int gpio,
36762306a36Sopenharmony_ci		       struct vgpio_irq_line *irq_line)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	bool ignore = false;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	raw_spin_lock(&vgpio->eventq_lock);
37262306a36Sopenharmony_ci	irq_line->queued = false;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Interrupt is disabled currently */
37562306a36Sopenharmony_ci	if (irq_line->masked || irq_line->disabled) {
37662306a36Sopenharmony_ci		ignore = true;
37762306a36Sopenharmony_ci		goto unlock;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/*
38162306a36Sopenharmony_ci	 * Buffer is returned as the interrupt was disabled earlier, but is
38262306a36Sopenharmony_ci	 * enabled again now. Requeue the buffers.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	if (irq_line->ires.status == VIRTIO_GPIO_IRQ_STATUS_INVALID) {
38562306a36Sopenharmony_ci		virtio_gpio_irq_prepare(vgpio, gpio);
38662306a36Sopenharmony_ci		ignore = true;
38762306a36Sopenharmony_ci		goto unlock;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (WARN_ON(irq_line->ires.status != VIRTIO_GPIO_IRQ_STATUS_VALID))
39162306a36Sopenharmony_ci		ignore = true;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ciunlock:
39462306a36Sopenharmony_ci	raw_spin_unlock(&vgpio->eventq_lock);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return ignore;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void virtio_gpio_event_vq(struct virtqueue *vq)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct virtio_gpio *vgpio = vq->vdev->priv;
40262306a36Sopenharmony_ci	struct device *dev = &vgpio->vdev->dev;
40362306a36Sopenharmony_ci	struct vgpio_irq_line *irq_line;
40462306a36Sopenharmony_ci	int gpio, ret;
40562306a36Sopenharmony_ci	unsigned int len;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	while (true) {
40862306a36Sopenharmony_ci		irq_line = virtqueue_get_buf(vgpio->event_vq, &len);
40962306a36Sopenharmony_ci		if (!irq_line)
41062306a36Sopenharmony_ci			break;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		if (len != sizeof(irq_line->ires)) {
41362306a36Sopenharmony_ci			dev_err(dev, "irq with incorrect length (%u : %u)\n",
41462306a36Sopenharmony_ci				len, (unsigned int)sizeof(irq_line->ires));
41562306a36Sopenharmony_ci			continue;
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		/*
41962306a36Sopenharmony_ci		 * Find GPIO line number from the offset of irq_line within the
42062306a36Sopenharmony_ci		 * irq_lines block. We can also get GPIO number from
42162306a36Sopenharmony_ci		 * irq-request, but better not to rely on a buffer returned by
42262306a36Sopenharmony_ci		 * remote.
42362306a36Sopenharmony_ci		 */
42462306a36Sopenharmony_ci		gpio = irq_line - vgpio->irq_lines;
42562306a36Sopenharmony_ci		WARN_ON(gpio >= vgpio->gc.ngpio);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		if (unlikely(ignore_irq(vgpio, gpio, irq_line)))
42862306a36Sopenharmony_ci			continue;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		ret = generic_handle_domain_irq(vgpio->gc.irq.domain, gpio);
43162306a36Sopenharmony_ci		if (ret)
43262306a36Sopenharmony_ci			dev_err(dev, "failed to handle interrupt: %d\n", ret);
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic void virtio_gpio_request_vq(struct virtqueue *vq)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct virtio_gpio_line *line;
43962306a36Sopenharmony_ci	unsigned int len;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	do {
44262306a36Sopenharmony_ci		line = virtqueue_get_buf(vq, &len);
44362306a36Sopenharmony_ci		if (!line)
44462306a36Sopenharmony_ci			return;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		line->rxlen = len;
44762306a36Sopenharmony_ci		complete(&line->completion);
44862306a36Sopenharmony_ci	} while (1);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void virtio_gpio_free_vqs(struct virtio_device *vdev)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	virtio_reset_device(vdev);
45462306a36Sopenharmony_ci	vdev->config->del_vqs(vdev);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio,
45862306a36Sopenharmony_ci				 struct virtio_device *vdev)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	const char * const names[] = { "requestq", "eventq" };
46162306a36Sopenharmony_ci	vq_callback_t *cbs[] = {
46262306a36Sopenharmony_ci		virtio_gpio_request_vq,
46362306a36Sopenharmony_ci		virtio_gpio_event_vq,
46462306a36Sopenharmony_ci	};
46562306a36Sopenharmony_ci	struct virtqueue *vqs[2] = { NULL, NULL };
46662306a36Sopenharmony_ci	int ret;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	ret = virtio_find_vqs(vdev, vgpio->irq_lines ? 2 : 1, vqs, cbs, names, NULL);
46962306a36Sopenharmony_ci	if (ret) {
47062306a36Sopenharmony_ci		dev_err(&vdev->dev, "failed to find vqs: %d\n", ret);
47162306a36Sopenharmony_ci		return ret;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (!vqs[0]) {
47562306a36Sopenharmony_ci		dev_err(&vdev->dev, "failed to find requestq vq\n");
47662306a36Sopenharmony_ci		goto out;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	vgpio->request_vq = vqs[0];
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (vgpio->irq_lines && !vqs[1]) {
48162306a36Sopenharmony_ci		dev_err(&vdev->dev, "failed to find eventq vq\n");
48262306a36Sopenharmony_ci		goto out;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	vgpio->event_vq = vqs[1];
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return 0;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ciout:
48962306a36Sopenharmony_ci	if (vqs[0] || vqs[1])
49062306a36Sopenharmony_ci		virtio_gpio_free_vqs(vdev);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return -ENODEV;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic const char **virtio_gpio_get_names(struct virtio_gpio *vgpio,
49662306a36Sopenharmony_ci					  u32 gpio_names_size, u16 ngpio)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct virtio_gpio_response_get_names *res;
49962306a36Sopenharmony_ci	struct device *dev = &vgpio->vdev->dev;
50062306a36Sopenharmony_ci	u8 *gpio_names, *str;
50162306a36Sopenharmony_ci	const char **names;
50262306a36Sopenharmony_ci	int i, ret, len;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (!gpio_names_size)
50562306a36Sopenharmony_ci		return NULL;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	len = sizeof(*res) + gpio_names_size;
50862306a36Sopenharmony_ci	res = devm_kzalloc(dev, len, GFP_KERNEL);
50962306a36Sopenharmony_ci	if (!res)
51062306a36Sopenharmony_ci		return NULL;
51162306a36Sopenharmony_ci	gpio_names = res->value;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ret = _virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_NAMES, 0, 0, NULL,
51462306a36Sopenharmony_ci			       res, len);
51562306a36Sopenharmony_ci	if (ret) {
51662306a36Sopenharmony_ci		dev_err(dev, "Failed to get GPIO names: %d\n", ret);
51762306a36Sopenharmony_ci		return NULL;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	names = devm_kcalloc(dev, ngpio, sizeof(*names), GFP_KERNEL);
52162306a36Sopenharmony_ci	if (!names)
52262306a36Sopenharmony_ci		return NULL;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* NULL terminate the string instead of checking it */
52562306a36Sopenharmony_ci	gpio_names[gpio_names_size - 1] = '\0';
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	for (i = 0, str = gpio_names; i < ngpio; i++) {
52862306a36Sopenharmony_ci		names[i] = str;
52962306a36Sopenharmony_ci		str += strlen(str) + 1; /* zero-length strings are allowed */
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		if (str > gpio_names + gpio_names_size) {
53262306a36Sopenharmony_ci			dev_err(dev, "gpio_names block is too short (%d)\n", i);
53362306a36Sopenharmony_ci			return NULL;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return names;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int virtio_gpio_probe(struct virtio_device *vdev)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct virtio_gpio_config config;
54362306a36Sopenharmony_ci	struct device *dev = &vdev->dev;
54462306a36Sopenharmony_ci	struct virtio_gpio *vgpio;
54562306a36Sopenharmony_ci	u32 gpio_names_size;
54662306a36Sopenharmony_ci	u16 ngpio;
54762306a36Sopenharmony_ci	int ret, i;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	vgpio = devm_kzalloc(dev, sizeof(*vgpio), GFP_KERNEL);
55062306a36Sopenharmony_ci	if (!vgpio)
55162306a36Sopenharmony_ci		return -ENOMEM;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Read configuration */
55462306a36Sopenharmony_ci	virtio_cread_bytes(vdev, 0, &config, sizeof(config));
55562306a36Sopenharmony_ci	gpio_names_size = le32_to_cpu(config.gpio_names_size);
55662306a36Sopenharmony_ci	ngpio = le16_to_cpu(config.ngpio);
55762306a36Sopenharmony_ci	if (!ngpio) {
55862306a36Sopenharmony_ci		dev_err(dev, "Number of GPIOs can't be zero\n");
55962306a36Sopenharmony_ci		return -EINVAL;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	vgpio->lines = devm_kcalloc(dev, ngpio, sizeof(*vgpio->lines), GFP_KERNEL);
56362306a36Sopenharmony_ci	if (!vgpio->lines)
56462306a36Sopenharmony_ci		return -ENOMEM;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	for (i = 0; i < ngpio; i++) {
56762306a36Sopenharmony_ci		mutex_init(&vgpio->lines[i].lock);
56862306a36Sopenharmony_ci		init_completion(&vgpio->lines[i].completion);
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	mutex_init(&vgpio->lock);
57262306a36Sopenharmony_ci	vdev->priv = vgpio;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	vgpio->vdev			= vdev;
57562306a36Sopenharmony_ci	vgpio->gc.free			= virtio_gpio_free;
57662306a36Sopenharmony_ci	vgpio->gc.get_direction		= virtio_gpio_get_direction;
57762306a36Sopenharmony_ci	vgpio->gc.direction_input	= virtio_gpio_direction_input;
57862306a36Sopenharmony_ci	vgpio->gc.direction_output	= virtio_gpio_direction_output;
57962306a36Sopenharmony_ci	vgpio->gc.get			= virtio_gpio_get;
58062306a36Sopenharmony_ci	vgpio->gc.set			= virtio_gpio_set;
58162306a36Sopenharmony_ci	vgpio->gc.ngpio			= ngpio;
58262306a36Sopenharmony_ci	vgpio->gc.base			= -1; /* Allocate base dynamically */
58362306a36Sopenharmony_ci	vgpio->gc.label			= dev_name(dev);
58462306a36Sopenharmony_ci	vgpio->gc.parent		= dev;
58562306a36Sopenharmony_ci	vgpio->gc.owner			= THIS_MODULE;
58662306a36Sopenharmony_ci	vgpio->gc.can_sleep		= true;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Interrupt support */
58962306a36Sopenharmony_ci	if (virtio_has_feature(vdev, VIRTIO_GPIO_F_IRQ)) {
59062306a36Sopenharmony_ci		vgpio->irq_lines = devm_kcalloc(dev, ngpio, sizeof(*vgpio->irq_lines), GFP_KERNEL);
59162306a36Sopenharmony_ci		if (!vgpio->irq_lines)
59262306a36Sopenharmony_ci			return -ENOMEM;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		/* The event comes from the outside so no parent handler */
59562306a36Sopenharmony_ci		vgpio->gc.irq.parent_handler	= NULL;
59662306a36Sopenharmony_ci		vgpio->gc.irq.num_parents	= 0;
59762306a36Sopenharmony_ci		vgpio->gc.irq.parents		= NULL;
59862306a36Sopenharmony_ci		vgpio->gc.irq.default_type	= IRQ_TYPE_NONE;
59962306a36Sopenharmony_ci		vgpio->gc.irq.handler		= handle_level_irq;
60062306a36Sopenharmony_ci		vgpio->gc.irq.chip		= &vgpio_irq_chip;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		for (i = 0; i < ngpio; i++) {
60362306a36Sopenharmony_ci			vgpio->irq_lines[i].type = VIRTIO_GPIO_IRQ_TYPE_NONE;
60462306a36Sopenharmony_ci			vgpio->irq_lines[i].disabled = true;
60562306a36Sopenharmony_ci			vgpio->irq_lines[i].masked = true;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		mutex_init(&vgpio->irq_lock);
60962306a36Sopenharmony_ci		raw_spin_lock_init(&vgpio->eventq_lock);
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ret = virtio_gpio_alloc_vqs(vgpio, vdev);
61362306a36Sopenharmony_ci	if (ret)
61462306a36Sopenharmony_ci		return ret;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Mark the device ready to perform operations from within probe() */
61762306a36Sopenharmony_ci	virtio_device_ready(vdev);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	vgpio->gc.names = virtio_gpio_get_names(vgpio, gpio_names_size, ngpio);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	ret = gpiochip_add_data(&vgpio->gc, vgpio);
62262306a36Sopenharmony_ci	if (ret) {
62362306a36Sopenharmony_ci		virtio_gpio_free_vqs(vdev);
62462306a36Sopenharmony_ci		dev_err(dev, "Failed to add virtio-gpio controller\n");
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return ret;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic void virtio_gpio_remove(struct virtio_device *vdev)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct virtio_gpio *vgpio = vdev->priv;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	gpiochip_remove(&vgpio->gc);
63562306a36Sopenharmony_ci	virtio_gpio_free_vqs(vdev);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic const struct virtio_device_id id_table[] = {
63962306a36Sopenharmony_ci	{ VIRTIO_ID_GPIO, VIRTIO_DEV_ANY_ID },
64062306a36Sopenharmony_ci	{},
64162306a36Sopenharmony_ci};
64262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, id_table);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic const unsigned int features[] = {
64562306a36Sopenharmony_ci	VIRTIO_GPIO_F_IRQ,
64662306a36Sopenharmony_ci};
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic struct virtio_driver virtio_gpio_driver = {
64962306a36Sopenharmony_ci	.feature_table		= features,
65062306a36Sopenharmony_ci	.feature_table_size	= ARRAY_SIZE(features),
65162306a36Sopenharmony_ci	.id_table		= id_table,
65262306a36Sopenharmony_ci	.probe			= virtio_gpio_probe,
65362306a36Sopenharmony_ci	.remove			= virtio_gpio_remove,
65462306a36Sopenharmony_ci	.driver			= {
65562306a36Sopenharmony_ci		.name		= KBUILD_MODNAME,
65662306a36Sopenharmony_ci		.owner		= THIS_MODULE,
65762306a36Sopenharmony_ci	},
65862306a36Sopenharmony_ci};
65962306a36Sopenharmony_cimodule_virtio_driver(virtio_gpio_driver);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ciMODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
66262306a36Sopenharmony_ciMODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
66362306a36Sopenharmony_ciMODULE_DESCRIPTION("VirtIO GPIO driver");
66462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
665