drm/nouveau/gpio: use event interfaces for interrupt signalling
authorBen Skeggs <bskeggs@redhat.com>
Sun, 3 Feb 2013 02:56:16 +0000 (12:56 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 20 Feb 2013 06:00:50 +0000 (16:00 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_dp.c

index 43cd20521a9480d73f360242ffb41c83176af750..b0007b50856763498a34b3874855b6f5f6a53fff 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <core/subdev.h>
 #include <core/device.h>
+#include <core/event.h>
 
 #include <subdev/bios.h>
 #include <subdev/bios/gpio.h>
 struct nouveau_gpio {
        struct nouveau_subdev base;
 
+       struct nouveau_event *events;
+
        /* hardware interfaces */
        void (*reset)(struct nouveau_gpio *, u8 func);
        int  (*drive)(struct nouveau_gpio *, int line, int dir, int out);
        int  (*sense)(struct nouveau_gpio *, int line);
-       void (*irq_enable)(struct nouveau_gpio *, int line, bool);
 
        /* software interfaces */
        int  (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
                     struct dcb_gpio_func *);
        int  (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
        int  (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
-       int  (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on);
-
-       /* interrupt handling */
-       struct list_head isr;
-       spinlock_t lock;
-
-       void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask);
-       int  (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
-                       void (*)(void *, int state), void *data);
-       void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
-                       void (*)(void *, int state), void *data);
 };
 
 static inline struct nouveau_gpio *
@@ -42,14 +33,17 @@ nouveau_gpio(void *obj)
 
 #define nouveau_gpio_create(p,e,o,l,d)                                         \
        nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d)
-#define nouveau_gpio_destroy(p)                                                \
-       nouveau_subdev_destroy(&(p)->base)
+#define nouveau_gpio_destroy(p) ({                                             \
+       struct nouveau_gpio *gpio = (p);                                       \
+       _nouveau_gpio_dtor(nv_object(gpio));                                   \
+})
 #define nouveau_gpio_fini(p,s)                                                 \
        nouveau_subdev_fini(&(p)->base, (s))
 
-int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
-                        struct nouveau_oclass *, int, int, void **);
-int nouveau_gpio_init(struct nouveau_gpio *);
+int  nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, int, int, void **);
+void _nouveau_gpio_dtor(struct nouveau_object *);
+int  nouveau_gpio_init(struct nouveau_gpio *);
 
 extern struct nouveau_oclass nv10_gpio_oclass;
 extern struct nouveau_oclass nv50_gpio_oclass;
@@ -59,6 +53,7 @@ void nv50_gpio_dtor(struct nouveau_object *);
 int  nv50_gpio_init(struct nouveau_object *);
 int  nv50_gpio_fini(struct nouveau_object *, bool);
 void nv50_gpio_intr(struct nouveau_subdev *);
-void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool);
+void nv50_gpio_intr_enable(struct nouveau_event *, int line);
+void nv50_gpio_intr_disable(struct nouveau_event *, int line);
 
 #endif
index 6f574fdc27c11518c43c566f5832de13be82b9c5..d422acc9af156bc0ab2cdea474d37d0691e4e9ba 100644 (file)
@@ -102,129 +102,12 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
        return ret;
 }
 
-static int
-nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on)
-{
-       struct dcb_gpio_func func;
-       int ret;
-
-       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
-       if (ret == 0) {
-               if (idx == 0 && gpio->irq_enable)
-                       gpio->irq_enable(gpio, func.line, on);
-               else
-                       ret = -ENODEV;
-       }
-
-       return ret;
-}
-
-struct gpio_isr {
-       struct nouveau_gpio *gpio;
-       struct list_head head;
-       struct work_struct work;
-       int idx;
-       struct dcb_gpio_func func;
-       void (*handler)(void *, int);
-       void *data;
-       bool inhibit;
-};
-
-static void
-nouveau_gpio_isr_bh(struct work_struct *work)
-{
-       struct gpio_isr *isr = container_of(work, struct gpio_isr, work);
-       struct nouveau_gpio *gpio = isr->gpio;
-       unsigned long flags;
-       int state;
-
-       state = nouveau_gpio_get(gpio, isr->idx, isr->func.func,
-                                                isr->func.line);
-       if (state >= 0)
-               isr->handler(isr->data, state);
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       isr->inhibit = false;
-       spin_unlock_irqrestore(&gpio->lock, flags);
-}
-
-static void
-nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask)
-{
-       struct gpio_isr *isr;
-
-       if (idx != 0)
-               return;
-
-       spin_lock(&gpio->lock);
-       list_for_each_entry(isr, &gpio->isr, head) {
-               if (line_mask & (1 << isr->func.line)) {
-                       if (isr->inhibit)
-                               continue;
-                       isr->inhibit = true;
-                       schedule_work(&isr->work);
-               }
-       }
-       spin_unlock(&gpio->lock);
-}
-
-static int
-nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
-                    void (*handler)(void *, int), void *data)
-{
-       struct gpio_isr *isr;
-       unsigned long flags;
-       int ret;
-
-       isr = kzalloc(sizeof(*isr), GFP_KERNEL);
-       if (!isr)
-               return -ENOMEM;
-
-       ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func);
-       if (ret) {
-               kfree(isr);
-               return ret;
-       }
-
-       INIT_WORK(&isr->work, nouveau_gpio_isr_bh);
-       isr->gpio = gpio;
-       isr->handler = handler;
-       isr->data = data;
-       isr->idx = idx;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       list_add(&isr->head, &gpio->isr);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-       return 0;
-}
-
-static void
-nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
-                    void (*handler)(void *, int), void *data)
+void
+_nouveau_gpio_dtor(struct nouveau_object *object)
 {
-       struct gpio_isr *isr, *tmp;
-       struct dcb_gpio_func func;
-       unsigned long flags;
-       LIST_HEAD(tofree);
-       int ret;
-
-       ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
-       if (ret == 0) {
-               spin_lock_irqsave(&gpio->lock, flags);
-               list_for_each_entry_safe(isr, tmp, &gpio->isr, head) {
-                       if (memcmp(&isr->func, &func, sizeof(func)) ||
-                           isr->idx != idx ||
-                           isr->handler != handler || isr->data != data)
-                               continue;
-                       list_move_tail(&isr->head, &tofree);
-               }
-               spin_unlock_irqrestore(&gpio->lock, flags);
-
-               list_for_each_entry_safe(isr, tmp, &tofree, head) {
-                       flush_work(&isr->work);
-                       kfree(isr);
-               }
-       }
+       struct nouveau_gpio *gpio = (void *)object;
+       nouveau_event_destroy(&gpio->events);
+       nouveau_subdev_destroy(&gpio->base);
 }
 
 int
@@ -242,15 +125,13 @@ nouveau_gpio_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       ret = nouveau_event_create(lines, &gpio->events);
+       if (ret)
+               return ret;
+
        gpio->find = nouveau_gpio_find;
        gpio->set  = nouveau_gpio_set;
        gpio->get  = nouveau_gpio_get;
-       gpio->irq  = nouveau_gpio_irq;
-       gpio->isr_run = nouveau_gpio_isr_run;
-       gpio->isr_add = nouveau_gpio_isr_add;
-       gpio->isr_del = nouveau_gpio_isr_del;
-       INIT_LIST_HEAD(&gpio->isr);
-       spin_lock_init(&gpio->lock);
        return 0;
 }
 
index cf38d2a1d7f126d658713787b63ff354f553d2de..9665f5f70ee3f5a11dc4ed04bd3304f4f6425fc3 100644 (file)
@@ -82,15 +82,6 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
        return 0;
 }
 
-static void
-nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
-{
-       u32 mask = 0x00010001 << line;
-
-       nv_wr32(gpio, 0x001104, mask);
-       nv_mask(gpio, 0x001144, mask, on ? mask : 0);
-}
-
 static void
 nv10_gpio_intr(struct nouveau_subdev *subdev)
 {
@@ -98,12 +89,30 @@ nv10_gpio_intr(struct nouveau_subdev *subdev)
        u32 intr = nv_rd32(priv, 0x001104);
        u32 hi = (intr & 0x0000ffff) >> 0;
        u32 lo = (intr & 0xffff0000) >> 16;
+       int i;
 
-       priv->base.isr_run(&priv->base, 0, hi | lo);
+       for (i = 0; (hi | lo) && i < 32; i++) {
+               if ((hi | lo) & (1 << i))
+                       nouveau_event_trigger(priv->base.events, i);
+       }
 
        nv_wr32(priv, 0x001104, intr);
 }
 
+static void
+nv10_gpio_intr_enable(struct nouveau_event *event, int line)
+{
+       nv_wr32(event->priv, 0x001104, 0x00010001 << line);
+       nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line);
+}
+
+static void
+nv10_gpio_intr_disable(struct nouveau_event *event, int line)
+{
+       nv_wr32(event->priv, 0x001104, 0x00010001 << line);
+       nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000);
+}
+
 static int
 nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -119,7 +128,9 @@ nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        priv->base.drive = nv10_gpio_drive;
        priv->base.sense = nv10_gpio_sense;
-       priv->base.irq_enable = nv10_gpio_irq_enable;
+       priv->base.events->priv = priv;
+       priv->base.events->enable = nv10_gpio_intr_enable;
+       priv->base.events->disable = nv10_gpio_intr_disable;
        nv_subdev(priv)->intr = nv10_gpio_intr;
        return 0;
 }
index dd022a5787b6fdc99a45b2b5918c96776f9aaa72..cbe609aa237c26146d18d453db444dc91809d854 100644 (file)
@@ -94,22 +94,13 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
        return !!(nv_rd32(gpio, reg) & (4 << shift));
 }
 
-void
-nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
-{
-       u32 reg  = line < 16 ? 0xe050 : 0xe070;
-       u32 mask = 0x00010001 << (line & 0xf);
-
-       nv_wr32(gpio, reg + 4, mask);
-       nv_mask(gpio, reg + 0, mask, on ? mask : 0);
-}
-
 void
 nv50_gpio_intr(struct nouveau_subdev *subdev)
 {
        struct nv50_gpio_priv *priv = (void *)subdev;
        u32 intr0, intr1 = 0;
        u32 hi, lo;
+       int i;
 
        intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
        if (nv_device(priv)->chipset >= 0x90)
@@ -117,13 +108,35 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
 
        hi = (intr0 & 0x0000ffff) | (intr1 << 16);
        lo = (intr0 >> 16) | (intr1 & 0xffff0000);
-       priv->base.isr_run(&priv->base, 0, hi | lo);
+
+       for (i = 0; (hi | lo) && i < 32; i++) {
+               if ((hi | lo) & (1 << i))
+                       nouveau_event_trigger(priv->base.events, i);
+       }
 
        nv_wr32(priv, 0xe054, intr0);
        if (nv_device(priv)->chipset >= 0x90)
                nv_wr32(priv, 0xe074, intr1);
 }
 
+void
+nv50_gpio_intr_enable(struct nouveau_event *event, int line)
+{
+       const u32 addr = line < 16 ? 0xe050 : 0xe070;
+       const u32 mask = 0x00010001 << (line & 0xf);
+       nv_wr32(event->priv, addr + 0x04, mask);
+       nv_mask(event->priv, addr + 0x00, mask, mask);
+}
+
+void
+nv50_gpio_intr_disable(struct nouveau_event *event, int line)
+{
+       const u32 addr = line < 16 ? 0xe050 : 0xe070;
+       const u32 mask = 0x00010001 << (line & 0xf);
+       nv_wr32(event->priv, addr + 0x04, mask);
+       nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
+}
+
 static int
 nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -142,7 +155,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->base.reset = nv50_gpio_reset;
        priv->base.drive = nv50_gpio_drive;
        priv->base.sense = nv50_gpio_sense;
-       priv->base.irq_enable = nv50_gpio_irq_enable;
+       priv->base.events->priv = priv;
+       priv->base.events->enable = nv50_gpio_intr_enable;
+       priv->base.events->disable = nv50_gpio_intr_disable;
        nv_subdev(priv)->intr = nv50_gpio_intr;
        return 0;
 }
index bc74199259a2017286481e9a84c67168f32dda17..5ef16a262de72d7f19e3a88e461585e2910a7ded 100644 (file)
@@ -88,7 +88,9 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->base.reset = nvd0_gpio_reset;
        priv->base.drive = nvd0_gpio_drive;
        priv->base.sense = nvd0_gpio_sense;
-       priv->base.irq_enable = nv50_gpio_irq_enable;
+       priv->base.events->priv = priv;
+       priv->base.events->enable = nv50_gpio_intr_enable;
+       priv->base.events->disable = nv50_gpio_intr_disable;
        nv_subdev(priv)->intr = nv50_gpio_intr;
        return 0;
 }
index a64e8777cbe9692f4b78c9805959bb15faea9190..9c4b3f5fba01e3be48c611306ba220f798e5792c 100644 (file)
@@ -55,8 +55,6 @@ MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
 static int nouveau_duallink = 1;
 module_param_named(duallink, nouveau_duallink, int, 0400);
 
-static void nouveau_connector_hotplug(void *, int);
-
 struct nouveau_encoder *
 find_encoder(struct drm_connector *connector, int type)
 {
@@ -100,22 +98,6 @@ static void
 nouveau_connector_destroy(struct drm_connector *connector)
 {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       struct nouveau_gpio *gpio;
-       struct nouveau_drm *drm;
-       struct drm_device *dev;
-
-       if (!nv_connector)
-               return;
-
-       dev  = nv_connector->base.dev;
-       drm  = nouveau_drm(dev);
-       gpio = nouveau_gpio(drm->device);
-
-       if (gpio && nv_connector->hpd.func != DCB_GPIO_UNUSED) {
-               gpio->isr_del(gpio, 0, nv_connector->hpd.func, 0xff,
-                             nouveau_connector_hotplug, connector);
-       }
-
        kfree(nv_connector->edid);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
@@ -912,6 +894,37 @@ nouveau_connector_funcs_lvds = {
        .force = nouveau_connector_force
 };
 
+static void
+nouveau_connector_hotplug_work(struct work_struct *work)
+{
+       struct nouveau_connector *nv_connector =
+               container_of(work, struct nouveau_connector, hpd_work);
+       struct drm_connector *connector = &nv_connector->base;
+       struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
+       bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff);
+
+       NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
+                drm_get_connector_name(connector));
+
+       if (plugged)
+               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+       else
+               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+
+       drm_helper_hpd_irq_event(dev);
+}
+
+static int
+nouveau_connector_hotplug(struct nouveau_eventh *event, int index)
+{
+       struct nouveau_connector *nv_connector =
+               container_of(event, struct nouveau_connector, hpd_func);
+       schedule_work(&nv_connector->hpd_work);
+       return NVKM_EVENT_KEEP;
+}
+
 static int
 drm_conntype_from_dcb(enum dcb_connector_type dcb)
 {
@@ -962,6 +975,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                return ERR_PTR(-ENOMEM);
 
        connector = &nv_connector->base;
+       INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work);
        nv_connector->index = index;
 
        /* attempt to parse vbios connector type and hotplug gpio */
@@ -978,6 +992,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
 
                ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
                                 DCB_GPIO_UNUSED, &nv_connector->hpd);
+               nv_connector->hpd_func.func = nouveau_connector_hotplug;
                if (ret)
                        nv_connector->hpd.func = DCB_GPIO_UNUSED;
 
@@ -1129,31 +1144,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
        }
 
        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-       if (gpio && nv_connector->hpd.func != DCB_GPIO_UNUSED) {
-               ret = gpio->isr_add(gpio, 0, nv_connector->hpd.func, 0xff,
-                                   nouveau_connector_hotplug, connector);
-               if (ret == 0)
-                       connector->polled = DRM_CONNECTOR_POLL_HPD;
-       }
+       if (nv_connector->hpd.func != DCB_GPIO_UNUSED)
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        drm_sysfs_connector_add(connector);
        return connector;
 }
-
-static void
-nouveau_connector_hotplug(void *data, int plugged)
-{
-       struct drm_connector *connector = data;
-       struct drm_device *dev = connector->dev;
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un",
-                drm_get_connector_name(connector));
-
-       if (plugged)
-               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-       else
-               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-
-       drm_helper_hpd_irq_event(dev);
-}
index f37250c8469d1f701754d8863d540eba2c81c0d5..6e399aad491a0b284a059d2292c9092716a489d1 100644 (file)
@@ -30,6 +30,8 @@
 #include <drm/drm_edid.h>
 #include "nouveau_crtc.h"
 
+#include <core/event.h>
+
 #include <subdev/bios.h>
 #include <subdev/bios/gpio.h>
 
@@ -62,10 +64,13 @@ enum nouveau_dithering_depth {
 struct nouveau_connector {
        struct drm_connector base;
        enum dcb_connector_type type;
-       struct dcb_gpio_func hpd;
        u8 index;
        u8 *dcb;
 
+       struct dcb_gpio_func hpd;
+       struct work_struct hpd_work;
+       struct nouveau_eventh hpd_func;
+
        int dithering_mode;
        int dithering_depth;
        int scaling_mode;
index a698e79f99d900968e2db6bab392f8b3de59bbc8..78fc5aa5f5dc37867d642e7bb947ddec9a176f5a 100644 (file)
@@ -233,8 +233,10 @@ nouveau_display_init(struct drm_device *dev)
        /* enable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (gpio)
-                       gpio->irq(gpio, 0, conn->hpd.func, 0xff, true);
+               if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
+                       nouveau_event_get(gpio->events, conn->hpd.line,
+                                        &conn->hpd_func);
+               }
        }
 
        return ret;
@@ -251,8 +253,10 @@ nouveau_display_fini(struct drm_device *dev)
        /* disable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (gpio)
-                       gpio->irq(gpio, 0, conn->hpd.func, 0xff, false);
+               if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
+                       nouveau_event_put(gpio->events, conn->hpd.line,
+                                        &conn->hpd_func);
+               }
        }
 
        drm_kms_helper_poll_disable(dev);
index c273c2afed109484c613fdad163799c2976daeb5..a87c3674157fdf37bca73044a43650d793dc5c0f 100644 (file)
@@ -260,7 +260,8 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
         * we take during link training (DP_SET_POWER is one), we need
         * to ignore them for the moment to avoid races.
         */
-       gpio->irq(gpio, 0, nv_connector->hpd.func, 0xff, false);
+       nouveau_event_put(gpio->events, nv_connector->hpd.line,
+                        &nv_connector->hpd_func);
 
        /* enable down-spreading and execute pre-train script from vbios */
        dp_link_train_init(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
@@ -300,7 +301,8 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
        dp_link_train_fini(dev, &dp);
 
        /* re-enable hotplug detect */
-       gpio->irq(gpio, 0, nv_connector->hpd.func, 0xff, true);
+       nouveau_event_get(gpio->events, nv_connector->hpd.line,
+                        &nv_connector->hpd_func);
        return true;
 }