Re: gpio-omap: add support gpiolib bias (pull-up/down) flags?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

* Drew Fustini <drew@xxxxxxxx> [200415 23:37]:
> As Robert described, I wanted to make us of the new support for bias
> flags in the gpiolib uapi which allows userspace libraries like libgpiod
> set pull-up or pull-down on lines [0].
> 
> Is there no way for gpio-omap to call into the pinctrl-single backend to
> set the bias bits (PULLUDEN and PULLTYPESEL) in pad control registers?

It sure would be nice to improve some of this :) You should be able to
do this using the gpio-ranges binding with the following steps:

1. Add gpio-ranges to dts files

This should be done for all the pins that need handling, here's
just one line version:

gpio-ranges = <&pmx_core 0 15 1>;
                         |  | |
			 |  | +-- number of pins
			 |  +---- pin start
			 +------- gpio start

Some mappings can use larger ranges, while some pins just need
to be added separately.

2. Implement parsing of gpio-ranges to pinctrl-single.c

The following test patch I did a while back should get you started.

>From what I recall, the issue here the addressing. The addressing
ends up using an artiticial index of pin entries in the dts, while
it should use the read pinctrl device padconf offset.

Maybe Linus has some suggestion on how to deal with that?

3. Have gpio-omap.c call gpiod_direction_input(desc) and
   gpiod_to_irq(desc) for example for gpio interrupt pins

To do that, you need something like this in gpio-omap.c:

if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
	chips->chip.request = gpiochip_generic_request;
	chips->chip.free = gpiochip_generic_free;
}

Regards,

Tony

8< -------------------
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -149,6 +150,8 @@ struct pcs_soc_data {
  * @dev:	device entry
  * @np:		device tree node
  * @pctl:	pin controller device
+ * @gc:		optional gpio chip
+ * @nr_gpio:	optional number of gpio pins
  * @flags:	mask of PCS_FEAT_xxx values
  * @missing_nr_pinctrl_cells: for legacy binding, may go away
  * @socdata:	soc specific data
@@ -178,6 +181,8 @@ struct pcs_device {
 	struct device *dev;
 	struct device_node *np;
 	struct pinctrl_dev *pctl;
+	struct gpio_chip *gc;
+	int nr_gpio;
 	unsigned flags;
 #define PCS_CONTEXT_LOSS_OFF	(1 << 3)
 #define PCS_QUIRK_SHARED_IRQ	(1 << 2)
@@ -1340,6 +1345,8 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
 		mutex_lock(&pcs->mutex);
 		list_add_tail(&range->node, &pcs->gpiofuncs);
 		mutex_unlock(&pcs->mutex);
+
+		pcs->nr_gpio += range->npins;
 	}
 	return ret;
 }
@@ -1599,6 +1606,93 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs,
 	return 0;
 }
 
+static int pcs_gpio_find_by_offset(struct pcs_device *pcs, int offset)
+{
+
+}
+
+static int pcs_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u\n", __func__, offset);
+
+	return 0;
+}
+
+static void pcs_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u\n", __func__, offset);
+}
+
+static int pcs_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u\n", __func__, offset);
+
+	return 0;
+}
+
+static int pcs_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u\n", __func__, offset);
+
+	return -EINVAL;
+}
+
+static void pcs_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u value: %i\n",
+		 __func__, offset, value);
+}
+
+static int pcs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+	struct pcs_device *pcs = gpiochip_get_data(gc);
+
+	dev_info(pcs->dev, "XXX %s offset: %u\n", __func__, offset);
+
+	return 0;
+}
+
+static int pcs_init_gpiochip(struct device_node *np, struct pcs_device *pcs)
+{
+	int error;
+
+	if (!pcs->nr_gpio || !of_property_read_bool(np, "gpio-controller"))
+		return 0;
+
+	pcs->gc = devm_kzalloc(pcs->dev, sizeof(*pcs->gc), GFP_KERNEL);
+	if (!pcs->gc)
+		return -ENOMEM;
+
+	pcs->gc->request = pcs_gpio_request;
+	pcs->gc->free = pcs_gpio_free;
+	pcs->gc->direction_input = pcs_gpio_direction_input;
+	pcs->gc->get = pcs_gpio_get;
+	pcs->gc->set = pcs_gpio_set;
+	pcs->gc->to_irq = pcs_gpio_to_irq;
+
+	pcs->gc->label = pcs->desc.name;
+	pcs->gc->parent = pcs->dev;
+	pcs->gc->owner = THIS_MODULE;
+	pcs->gc->base = -1;
+	pcs->gc->ngpio = pcs->nr_gpio;
+
+	error = devm_gpiochip_add_data(pcs->dev, pcs->gc, pcs);
+	if (error)
+		return error;
+
+	return 0;
+}
+
 #ifdef CONFIG_PM
 static int pcs_save_context(struct pcs_device *pcs)
 {
@@ -1868,6 +1962,10 @@ static int pcs_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto free;
 
+	ret = pcs_init_gpiochip(np, pcs);
+	if (ret < 0)
+		goto free;
+
 	pcs->socdata.irq = irq_of_parse_and_map(np, 0);
 	if (pcs->socdata.irq)
 		pcs->flags |= PCS_FEAT_IRQ;
-- 
2.26.1



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux