]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
Merge tag 'v3.16-rc1' into i2c/for-next
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / core / subdev / gpio / base.c
index f572c2804c325f01896c061988626eb91b8e2f40..45e0202f3151868ab4b8d95587747a2f280ff7a1 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/gpio.h>
 #include <subdev/bios.h>
 #include <subdev/bios/gpio.h>
 
+#include "priv.h"
+
 static int
 nouveau_gpio_drive(struct nouveau_gpio *gpio,
                   int idx, int line, int dir, int out)
 {
-       return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV;
+       const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+       return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
 }
 
 static int
 nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
 {
-       return gpio->sense ? gpio->sense(gpio, line) : -ENODEV;
+       const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+       return impl->sense ? impl->sense(gpio, line) : -ENODEV;
 }
 
 static int
@@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
        return ret;
 }
 
+static void
+nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
+       const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+       impl->intr_mask(gpio, type, 1 << index, 0);
+}
+
+static void
+nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
+       const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+       impl->intr_mask(gpio, type, 1 << index, 1 << index);
+}
+
+static void
+nouveau_gpio_intr(struct nouveau_subdev *subdev)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(subdev);
+       const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+       u32 hi, lo, e, i;
+
+       impl->intr_stat(gpio, &hi, &lo);
+
+       for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) {
+               if (hi & (1 << i))
+                       e |= NVKM_GPIO_HI;
+               if (lo & (1 << i))
+                       e |= NVKM_GPIO_LO;
+               nouveau_event_trigger(gpio->events, e, i);
+       }
+}
+
+int
+_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
+{
+       const struct nouveau_gpio_impl *impl = (void *)object->oclass;
+       struct nouveau_gpio *gpio = nouveau_gpio(object);
+       u32 mask = (1 << impl->lines) - 1;
+
+       impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
+       impl->intr_stat(gpio, &mask, &mask);
+
+       return nouveau_subdev_fini(&gpio->base, suspend);
+}
+
+static struct dmi_system_id gpio_reset_ids[] = {
+       {
+               .ident = "Apple Macbook 10,1",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
+               }
+       },
+       { }
+};
+
+int
+_nouveau_gpio_init(struct nouveau_object *object)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(object);
+       int ret;
+
+       ret = nouveau_subdev_init(&gpio->base);
+       if (ret)
+               return ret;
+
+       if (gpio->reset && dmi_check_system(gpio_reset_ids))
+               gpio->reset(gpio, DCB_GPIO_UNUSED);
+
+       return ret;
+}
+
 void
 _nouveau_gpio_dtor(struct nouveau_object *object)
 {
@@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object)
 int
 nouveau_gpio_create_(struct nouveau_object *parent,
                     struct nouveau_object *engine,
-                    struct nouveau_oclass *oclass, int lines,
+                    struct nouveau_oclass *oclass,
                     int length, void **pobject)
 {
+       const struct nouveau_gpio_impl *impl = (void *)oclass;
        struct nouveau_gpio *gpio;
        int ret;
 
@@ -125,34 +203,34 @@ 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->reset = impl->reset;
+
+       ret = nouveau_event_create(2, impl->lines, &gpio->events);
+       if (ret)
+               return ret;
+
+       gpio->events->priv = gpio;
+       gpio->events->enable = nouveau_gpio_intr_enable;
+       gpio->events->disable = nouveau_gpio_intr_disable;
+       nv_subdev(gpio)->intr = nouveau_gpio_intr;
        return 0;
 }
 
-static struct dmi_system_id gpio_reset_ids[] = {
-       {
-               .ident = "Apple Macbook 10,1",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
-               }
-       },
-       { }
-};
-
 int
-nouveau_gpio_init(struct nouveau_gpio *gpio)
+_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                  struct nouveau_oclass *oclass, void *data, u32 size,
+                  struct nouveau_object **pobject)
 {
-       int ret = nouveau_subdev_init(&gpio->base);
-       if (ret == 0 && gpio->reset) {
-               if (dmi_check_system(gpio_reset_ids))
-                       gpio->reset(gpio, DCB_GPIO_UNUSED);
-       }
-       return ret;
+       struct nouveau_gpio *gpio;
+       int ret;
+
+       ret = nouveau_gpio_create(parent, engine, oclass, &gpio);
+       *pobject = nv_object(gpio);
+       if (ret)
+               return ret;
+
+       return 0;
 }