0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/leds.h>
0032
0033 #include "nouveau_led.h"
0034 #include <nvkm/subdev/gpio.h>
0035
0036 static enum led_brightness
0037 nouveau_led_get_brightness(struct led_classdev *led)
0038 {
0039 struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
0040 struct nouveau_drm *drm = nouveau_drm(drm_dev);
0041 struct nvif_object *device = &drm->client.device.object;
0042 u32 div, duty;
0043
0044 div = nvif_rd32(device, 0x61c880) & 0x00ffffff;
0045 duty = nvif_rd32(device, 0x61c884) & 0x00ffffff;
0046
0047 if (div > 0)
0048 return duty * LED_FULL / div;
0049 else
0050 return 0;
0051 }
0052
0053 static void
0054 nouveau_led_set_brightness(struct led_classdev *led, enum led_brightness value)
0055 {
0056 struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
0057 struct nouveau_drm *drm = nouveau_drm(drm_dev);
0058 struct nvif_object *device = &drm->client.device.object;
0059
0060 u32 input_clk = 27e6;
0061 u32 freq = 100;
0062 u32 div, duty;
0063
0064 div = input_clk / freq;
0065 duty = value * div / LED_FULL;
0066
0067
0068
0069
0070
0071
0072 nvif_wr32(device, 0x61c880, div);
0073 nvif_wr32(device, 0x61c884, 0xc0000000 | duty);
0074 }
0075
0076
0077 int
0078 nouveau_led_init(struct drm_device *dev)
0079 {
0080 struct nouveau_drm *drm = nouveau_drm(dev);
0081 struct nvkm_gpio *gpio = nvxx_gpio(&drm->client.device);
0082 struct dcb_gpio_func logo_led;
0083 int ret;
0084
0085 if (!gpio)
0086 return 0;
0087
0088
0089 if (nvkm_gpio_find(gpio, 0, DCB_GPIO_LOGO_LED_PWM, 0xff, &logo_led))
0090 return 0;
0091
0092 drm->led = kzalloc(sizeof(*drm->led), GFP_KERNEL);
0093 if (!drm->led)
0094 return -ENOMEM;
0095 drm->led->dev = dev;
0096
0097 drm->led->led.name = "nvidia-logo";
0098 drm->led->led.max_brightness = 255;
0099 drm->led->led.brightness_get = nouveau_led_get_brightness;
0100 drm->led->led.brightness_set = nouveau_led_set_brightness;
0101
0102 ret = led_classdev_register(dev->dev, &drm->led->led);
0103 if (ret) {
0104 kfree(drm->led);
0105 drm->led = NULL;
0106 return ret;
0107 }
0108
0109 return 0;
0110 }
0111
0112 void
0113 nouveau_led_suspend(struct drm_device *dev)
0114 {
0115 struct nouveau_drm *drm = nouveau_drm(dev);
0116
0117 if (drm->led)
0118 led_classdev_suspend(&drm->led->led);
0119 }
0120
0121 void
0122 nouveau_led_resume(struct drm_device *dev)
0123 {
0124 struct nouveau_drm *drm = nouveau_drm(dev);
0125
0126 if (drm->led)
0127 led_classdev_resume(&drm->led->led);
0128 }
0129
0130 void
0131 nouveau_led_fini(struct drm_device *dev)
0132 {
0133 struct nouveau_drm *drm = nouveau_drm(dev);
0134
0135 if (drm->led) {
0136 led_classdev_unregister(&drm->led->led);
0137 kfree(drm->led);
0138 drm->led = NULL;
0139 }
0140 }