Author: adrian
Date: Sat May  6 06:22:14 2017
New Revision: 317874
URL: https://svnweb.freebsd.org/changeset/base/317874

Log:
  [mediatek] [gpio] add PPS / interrupt support.
  
  Submitted by: Hiroki Mori <yamori...@yahoo.co.jp>
  Reviewed by:  mizhka
  Differential Revision:        https://reviews.freebsd.org/D9784

Modified:
  head/sys/mips/mediatek/mtk_gpio_v1.c

Modified: head/sys/mips/mediatek/mtk_gpio_v1.c
==============================================================================
--- head/sys/mips/mediatek/mtk_gpio_v1.c        Sat May  6 06:20:34 2017        
(r317873)
+++ head/sys/mips/mediatek/mtk_gpio_v1.c        Sat May  6 06:22:14 2017        
(r317874)
@@ -292,7 +292,8 @@ mtk_gpio_attach(device_t dev)
 
        for (i = 0; i < sc->num_pins; i++) {
                sc->pins[i].pin_caps |= GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
-                   GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
+                   GPIO_PIN_INVIN | GPIO_PIN_INVOUT |
+                   GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING;
                sc->pins[i].intr_polarity = INTR_POLARITY_HIGH;
                sc->pins[i].intr_trigger = INTR_TRIGGER_EDGE;
 
@@ -500,22 +501,78 @@ out:
 }
 
 static int
+mtk_gpio_pic_map_fdt(struct mtk_gpio_softc *sc,
+    struct intr_map_data_fdt *daf, u_int *irqp, uint32_t *modep)
+{
+       u_int irq;
+
+       if (daf->ncells != 1) {
+               device_printf(sc->dev, "Invalid #interrupt-cells\n");
+               return (EINVAL);
+       }
+
+       irq = daf->cells[0];
+
+       if (irq >= sc->num_pins) {
+               device_printf(sc->dev, "Invalid interrupt number %u\n", irq);
+               return (EINVAL);
+       }
+
+       *irqp = irq;
+       if (modep != NULL)
+               *modep = GPIO_INTR_EDGE_BOTH;
+
+       return (0);
+}
+
+static int
+mtk_gpio_pic_map_gpio(struct mtk_gpio_softc *sc,
+    struct intr_map_data_gpio *dag, u_int *irqp, uint32_t *modep)
+{
+       u_int irq;
+
+       irq = dag->gpio_pin_num;
+       if (irq >= sc->num_pins) {
+               device_printf(sc->dev, "Invalid interrupt number %u\n", irq);
+               return (EINVAL);
+       }
+
+       *irqp = irq;
+       if (modep != NULL)
+               *modep = dag->gpio_intr_mode;
+
+       return (0);
+}
+
+static int
 mtk_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
     struct intr_irqsrc **isrcp)
 {
-       struct intr_map_data_fdt *daf;
+       int error;
+       u_int irq;
        struct mtk_gpio_softc *sc;
 
-       if (data->type != INTR_MAP_DATA_FDT)
-               return (ENOTSUP);
-
        sc = device_get_softc(dev);
-       daf = (struct intr_map_data_fdt *)data;
+       switch (data->type) {
+       case INTR_MAP_DATA_FDT:
+               error = (mtk_gpio_pic_map_fdt(sc, 
+                   (struct intr_map_data_fdt *)data, &irq, NULL));
+               break;
+       case INTR_MAP_DATA_GPIO:
+               error = (mtk_gpio_pic_map_gpio(sc, 
+                   (struct intr_map_data_gpio *)data, &irq, NULL));
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
 
-       if (daf->ncells != 1 || daf->cells[0] >= sc->num_pins)
-               return (EINVAL);
+       if (error != 0) {
+               device_printf(dev, "Invalid map type\n");
+               return (error);
+       }
 
-       *isrcp = PIC_INTR_ISRC(sc, daf->cells[0]);
+       *isrcp = PIC_INTR_ISRC(sc, irq);
        return (0);
 }
 
@@ -600,6 +657,51 @@ mtk_gpio_pic_post_filter(device_t dev, s
 }
 
 static int
+mtk_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+       struct mtk_gpio_softc *sc;
+       uint32_t val;
+       int error;
+       uint32_t mode;
+       u_int irq;
+
+       if (data == NULL)
+               return (ENOTSUP);
+
+       sc = device_get_softc(dev);
+
+       switch (data->type) {
+       case INTR_MAP_DATA_FDT:
+               error = mtk_gpio_pic_map_fdt(sc, 
+                   (struct intr_map_data_fdt *)data, &irq, &mode);
+               break;
+       case INTR_MAP_DATA_GPIO:
+               error = mtk_gpio_pic_map_gpio(sc, 
+                   (struct intr_map_data_gpio *)data, &irq, &mode);
+               break;
+       default:
+               error = ENOTSUP;
+               break;
+       }
+
+       if (error != 0)
+               return (error);
+       
+       MTK_GPIO_LOCK(sc);
+       if (mode == GPIO_INTR_EDGE_BOTH || mode == GPIO_INTR_EDGE_RISING) {
+               val = MTK_READ_4(sc, GPIO_PIORENA) | (1u << irq);
+               MTK_WRITE_4(sc, GPIO_PIORENA, val);
+       }
+       if (mode == GPIO_INTR_EDGE_BOTH || mode == GPIO_INTR_EDGE_FALLING) {
+               val = MTK_READ_4(sc, GPIO_PIOFENA) | (1u << irq);
+               MTK_WRITE_4(sc, GPIO_PIOFENA, val);
+       }
+       MTK_GPIO_UNLOCK(sc);
+       return (0);
+}
+
+static int
 mtk_gpio_intr(void *arg)
 {
        struct mtk_gpio_softc *sc;
@@ -607,6 +709,7 @@ mtk_gpio_intr(void *arg)
 
        sc = arg;
        interrupts = MTK_READ_4(sc, GPIO_PIOINT);
+       MTK_WRITE_4(sc, GPIO_PIOINT, interrupts);
 
        for (i = 0; interrupts != 0; i++, interrupts >>= 1) {
                if ((interrupts & 0x1) == 0)
@@ -649,6 +752,7 @@ static device_method_t mtk_gpio_methods[
        DEVMETHOD(pic_disable_intr,     mtk_gpio_pic_disable_intr),
        DEVMETHOD(pic_enable_intr,      mtk_gpio_pic_enable_intr),
        DEVMETHOD(pic_map_intr,         mtk_gpio_pic_map_intr),
+       DEVMETHOD(pic_setup_intr,       mtk_gpio_pic_setup_intr),
        DEVMETHOD(pic_post_filter,      mtk_gpio_pic_post_filter),
        DEVMETHOD(pic_post_ithread,     mtk_gpio_pic_post_ithread),
        DEVMETHOD(pic_pre_ithread,      mtk_gpio_pic_pre_ithread),
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to