Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Apr 2016 12:03:22 +0000 (UTC)
From:      Michal Meloun <mmel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r298738 - in head/sys: dev/gpio kern sys
Message-ID:  <201604281203.u3SC3MEG010980@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mmel
Date: Thu Apr 28 12:03:22 2016
New Revision: 298738
URL: https://svnweb.freebsd.org/changeset/base/298738

Log:
  GPIO: Add support for gpio pin interrupts.
  Add new function gpio_alloc_intr_resource(), which allows an allocation
  of interrupt resource associated to given gpio pin. It also allows to
  specify interrupt configuration.
  
  Note: This functionality is dependent on INTRNG, and must be
  implemented in each GPIO controller.

Modified:
  head/sys/dev/gpio/gpiobus.c
  head/sys/dev/gpio/gpiobusvar.h
  head/sys/kern/subr_intr.c
  head/sys/sys/gpio.h
  head/sys/sys/intr.h

Modified: head/sys/dev/gpio/gpiobus.c
==============================================================================
--- head/sys/dev/gpio/gpiobus.c	Thu Apr 28 09:40:24 2016	(r298737)
+++ head/sys/dev/gpio/gpiobus.c	Thu Apr 28 12:03:22 2016	(r298738)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/gpio.h>
+#include <sys/intr.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -72,6 +73,31 @@ static int gpiobus_pin_set(device_t, dev
 static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*);
 static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
 
+/*
+ * XXX -> Move me to better place - gpio_subr.c?
+ * Also, this function must be changed when interrupt configuration
+ * data will be moved into struct resource.
+ */
+#ifdef INTRNG
+struct resource *
+gpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags,
+    gpio_pin_t pin, uint32_t intr_mode)
+{
+	u_int irqnum;
+
+	/*
+	 * Allocate new fictitious interrupt number and store configuration
+	 * into it.
+	 */
+	irqnum = intr_gpio_map_irq(pin->dev, pin->pin, pin->flags, intr_mode);
+	if (irqnum == 0xFFFFFFFF)
+		return (NULL);
+
+	return (bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid,
+	    irqnum, irqnum, 1, alloc_flags));
+}
+#endif
+
 int
 gpio_check_flags(uint32_t caps, uint32_t flags)
 {

Modified: head/sys/dev/gpio/gpiobusvar.h
==============================================================================
--- head/sys/dev/gpio/gpiobusvar.h	Thu Apr 28 09:40:24 2016	(r298737)
+++ head/sys/dev/gpio/gpiobusvar.h	Thu Apr 28 12:03:22 2016	(r298738)
@@ -61,6 +61,9 @@
 #define	GPIOBUS_WAIT		1
 #define	GPIOBUS_DONTWAIT	2
 
+/* Use default interrupt mode -  for gpio_alloc_intr_resource */
+#define GPIO_INTR_CONFORM	GPIO_INTR_NONE
+
 struct gpiobus_pin_data
 {
 	int		mapped;		/* pin is mapped/reserved. */
@@ -122,6 +125,10 @@ int gpio_pin_is_active(gpio_pin_t pin, b
 int gpio_pin_set_active(gpio_pin_t pin, bool active);
 int gpio_pin_setflags(gpio_pin_t pin, uint32_t flags);
 #endif
+#ifdef INTRNG
+struct resource *gpio_alloc_intr_resource(device_t consumer_dev, int *rid,
+    u_int alloc_flags, gpio_pin_t pin, uint32_t intr_mode);
+#endif
 int gpio_check_flags(uint32_t, uint32_t);
 device_t gpiobus_attach_bus(device_t);
 int gpiobus_detach_bus(device_t);

Modified: head/sys/kern/subr_intr.c
==============================================================================
--- head/sys/kern/subr_intr.c	Thu Apr 28 09:40:24 2016	(r298737)
+++ head/sys/kern/subr_intr.c	Thu Apr 28 12:03:22 2016	(r298738)
@@ -596,6 +596,27 @@ intr_fdt_map_irq(phandle_t node, pcell_t
 }
 #endif
 
+/*
+ *  Store GPIO interrupt decription in framework and return unique interrupt
+ *  number (resource handle) associated with it.
+ */
+u_int
+intr_gpio_map_irq(device_t dev, u_int pin_num, u_int pin_flags, u_int intr_mode)
+{
+	struct intr_dev_data *ddata;
+
+	ddata = intr_ddata_alloc(0);
+	if (ddata == NULL)
+		return (0xFFFFFFFF);	/* no space left */
+
+	ddata->idd_dev = dev;
+	ddata->idd_data.type = INTR_MAP_DATA_GPIO;
+	ddata->idd_data.gpio.gpio_pin_num = pin_num;
+	ddata->idd_data.gpio.gpio_pin_flags = pin_flags;
+	ddata->idd_data.gpio.gpio_intr_mode = intr_mode;
+	return (ddata->idd_irq);
+}
+
 #ifdef INTR_SOLO
 /*
  *  Setup filter into interrupt source.

Modified: head/sys/sys/gpio.h
==============================================================================
--- head/sys/sys/gpio.h	Thu Apr 28 09:40:24 2016	(r298737)
+++ head/sys/sys/gpio.h	Thu Apr 28 12:03:22 2016	(r298738)
@@ -60,16 +60,26 @@
 #define GPIOMAXNAME		64
 
 /* GPIO pin configuration flags */
-#define GPIO_PIN_INPUT		0x0001	/* input direction */
-#define GPIO_PIN_OUTPUT		0x0002	/* output direction */
-#define GPIO_PIN_OPENDRAIN	0x0004	/* open-drain output */
-#define GPIO_PIN_PUSHPULL	0x0008	/* push-pull output */
-#define GPIO_PIN_TRISTATE	0x0010	/* output disabled */
-#define GPIO_PIN_PULLUP		0x0020	/* internal pull-up enabled */
-#define GPIO_PIN_PULLDOWN	0x0040	/* internal pull-down enabled */
-#define GPIO_PIN_INVIN		0x0080	/* invert input */
-#define GPIO_PIN_INVOUT		0x0100	/* invert output */
-#define GPIO_PIN_PULSATE	0x0200	/* pulsate in hardware */
+#define GPIO_PIN_INPUT		0x00000001	/* input direction */
+#define GPIO_PIN_OUTPUT		0x00000002	/* output direction */
+#define GPIO_PIN_OPENDRAIN	0x00000004	/* open-drain output */
+#define GPIO_PIN_PUSHPULL	0x00000008	/* push-pull output */
+#define GPIO_PIN_TRISTATE	0x00000010	/* output disabled */
+#define GPIO_PIN_PULLUP		0x00000020	/* internal pull-up enabled */
+#define GPIO_PIN_PULLDOWN	0x00000040	/* internal pull-down enabled */
+#define GPIO_PIN_INVIN		0x00000080	/* invert input */
+#define GPIO_PIN_INVOUT		0x00000100	/* invert output */
+#define GPIO_PIN_PULSATE	0x00000200	/* pulsate in hardware */
+/* GPIO interrupt capabilities */
+#define GPIO_INTR_NONE		0x00000000	/* no interrupt support */
+#define GPIO_INTR_LEVEL_LOW	0x00010000	/* level trigger, low */
+#define GPIO_INTR_LEVEL_HIGH	0x00020000	/* level trigger, high */
+#define GPIO_INTR_EDGE_RISING	0x00040000	/* edge trigger, rising */
+#define GPIO_INTR_EDGE_FALLING	0x00080000	/* edge trigger, falling */
+#define GPIO_INTR_EDGE_BOTH	0x00100000	/* edge trigger, both */
+#define GPIO_INTR_MASK		(GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | \
+				GPIO_INTR_EDGE_RISING |			      \
+				GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH)
 
 struct gpio_pin {
 	uint32_t gp_pin;			/* pin number */

Modified: head/sys/sys/intr.h
==============================================================================
--- head/sys/sys/intr.h	Thu Apr 28 09:40:24 2016	(r298737)
+++ head/sys/sys/intr.h	Thu Apr 28 12:03:22 2016	(r298738)
@@ -35,6 +35,7 @@
 enum intr_map_data_type {
 	INTR_MAP_DATA_ACPI,
 	INTR_MAP_DATA_FDT,
+	INTR_MAP_DATA_GPIO,
 };
 
 #ifdef DEV_ACPI
@@ -51,6 +52,12 @@ struct intr_map_data_fdt {
 };
 #endif
 
+struct intr_map_data_gpio {
+	u_int			gpio_pin_num;
+	u_int			gpio_pin_flags;
+	u_int		 	gpio_intr_mode;
+};
+
 struct intr_map_data {
 	enum intr_map_data_type	type;
 	union {
@@ -60,6 +67,7 @@ struct intr_map_data {
 #ifdef FDT
 		struct intr_map_data_fdt	fdt;
 #endif
+		struct intr_map_data_gpio	gpio;
 	};
 };
 
@@ -130,6 +138,8 @@ u_int intr_acpi_map_irq(device_t, u_int,
 #ifdef FDT
 u_int intr_fdt_map_irq(phandle_t, pcell_t *, u_int);
 #endif
+u_int intr_gpio_map_irq(device_t dev, u_int pin_num, u_int pin_flags,
+    u_int intr_mode);
 
 #ifdef SMP
 int intr_bind_irq(device_t, struct resource *, int);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604281203.u3SC3MEG010980>