mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
soc: fsl: qe: Avoid using gpio_to_desc()
The qe gpio driver is a custom API combined GPIO and pin control driver that exist outside of the pin control subsystem for historical reasons. We want to get rid of the old GPIO numberspace, so instead of calling gpio_to_desc() we get the gpio descriptor for the requested line from the device tree directly without passing through the GPIO numberspace, and then we get the gpiochip from the descriptor. Using the reference counting inside the gpio descriptor we can drop the reference counting code in this driver. A second gpiod_get() will not succeed. To obtain the local hardware offset of the GPIO line, the driver need to include the header from the gpiolib internals. This isn't pretty but it is the lesser evil compared to keeping the code as a roadblock to gpiolib refactoring. A proper solution would be to rewrite the driver as a real pin control driver with a built-in gpio_chip. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Cc: Bartosz Golaszewski <brgl@bgdev.pl> Cc: linux-gpio@vger.kernel.org Link: https://lore.kernel.org/r/20221027081108.174662-1-linus.walleij@linaro.org' Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
parent
247f34f7b8
commit
84582f9ed0
@ -14,20 +14,23 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
/* FIXME: needed for gpio_to_chip() get rid of this */
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <soc/fsl/qe/qe.h>
|
#include <soc/fsl/qe/qe.h>
|
||||||
|
/*
|
||||||
|
* FIXME: this is legacy code that is accessing gpiolib internals in order
|
||||||
|
* to implement a custom pin controller. The proper solution is to create
|
||||||
|
* a real combined pin control and GPIO driver in drivers/pinctrl. However
|
||||||
|
* this hack is here for legacy code reasons.
|
||||||
|
*/
|
||||||
|
#include "../../../gpio/gpiolib.h"
|
||||||
|
|
||||||
struct qe_gpio_chip {
|
struct qe_gpio_chip {
|
||||||
struct of_mm_gpio_chip mm_gc;
|
struct of_mm_gpio_chip mm_gc;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
unsigned long pin_flags[QE_PIO_PINS];
|
|
||||||
#define QE_PIN_REQUESTED 0
|
|
||||||
|
|
||||||
/* shadowed data register to clear/set bits safely */
|
/* shadowed data register to clear/set bits safely */
|
||||||
u32 cpdata;
|
u32 cpdata;
|
||||||
|
|
||||||
@ -144,6 +147,7 @@ struct qe_pin {
|
|||||||
* something like qe_pio_controller. Someday.
|
* something like qe_pio_controller. Someday.
|
||||||
*/
|
*/
|
||||||
struct qe_gpio_chip *controller;
|
struct qe_gpio_chip *controller;
|
||||||
|
struct gpio_desc *gpiod;
|
||||||
int num;
|
int num;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -160,9 +164,8 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
|||||||
{
|
{
|
||||||
struct qe_pin *qe_pin;
|
struct qe_pin *qe_pin;
|
||||||
struct gpio_chip *gc;
|
struct gpio_chip *gc;
|
||||||
struct qe_gpio_chip *qe_gc;
|
struct gpio_desc *gpiod;
|
||||||
int err;
|
int err;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
|
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
|
||||||
if (!qe_pin) {
|
if (!qe_pin) {
|
||||||
@ -170,38 +173,36 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
|||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = of_get_gpio(np, index);
|
gpiod = fwnode_gpiod_get_index(of_fwnode_handle(np), NULL, index, GPIOD_ASIS, "qe");
|
||||||
if (err < 0)
|
if (IS_ERR(gpiod)) {
|
||||||
|
err = PTR_ERR(gpiod);
|
||||||
goto err0;
|
goto err0;
|
||||||
gc = gpio_to_chip(err);
|
}
|
||||||
|
if (!gpiod) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
gc = gpiod_to_chip(gpiod);
|
||||||
if (WARN_ON(!gc)) {
|
if (WARN_ON(!gc)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
qe_pin->gpiod = gpiod;
|
||||||
|
qe_pin->controller = gpiochip_get_data(gc);
|
||||||
|
/*
|
||||||
|
* FIXME: this gets the local offset on the gpio_chip so that the driver
|
||||||
|
* can manipulate pin control settings through its custom API. The real
|
||||||
|
* solution is to create a real pin control driver for this.
|
||||||
|
*/
|
||||||
|
qe_pin->num = gpio_chip_hwgpio(gpiod);
|
||||||
|
|
||||||
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
|
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
|
||||||
pr_debug("%s: tried to get a non-qe pin\n", __func__);
|
pr_debug("%s: tried to get a non-qe pin\n", __func__);
|
||||||
|
gpiod_put(gpiod);
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
return qe_pin;
|
||||||
qe_gc = gpiochip_get_data(gc);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
|
||||||
|
|
||||||
err -= gc->base;
|
|
||||||
if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
|
|
||||||
qe_pin->controller = qe_gc;
|
|
||||||
qe_pin->num = err;
|
|
||||||
err = 0;
|
|
||||||
} else {
|
|
||||||
err = -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
|
||||||
|
|
||||||
if (!err)
|
|
||||||
return qe_pin;
|
|
||||||
err0:
|
err0:
|
||||||
kfree(qe_pin);
|
kfree(qe_pin);
|
||||||
pr_debug("%s failed with status %d\n", __func__, err);
|
pr_debug("%s failed with status %d\n", __func__, err);
|
||||||
@ -219,14 +220,7 @@ EXPORT_SYMBOL(qe_pin_request);
|
|||||||
*/
|
*/
|
||||||
void qe_pin_free(struct qe_pin *qe_pin)
|
void qe_pin_free(struct qe_pin *qe_pin)
|
||||||
{
|
{
|
||||||
struct qe_gpio_chip *qe_gc = qe_pin->controller;
|
gpiod_put(qe_pin->gpiod);
|
||||||
unsigned long flags;
|
|
||||||
const int pin = qe_pin->num;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
|
||||||
test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]);
|
|
||||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
|
||||||
|
|
||||||
kfree(qe_pin);
|
kfree(qe_pin);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(qe_pin_free);
|
EXPORT_SYMBOL(qe_pin_free);
|
||||||
|
Loading…
Reference in New Issue
Block a user