diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/gpio/base.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | 130 |
1 files changed, 104 insertions, 26 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index f572c28..45e0202 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -22,21 +22,24 @@ * 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; } |