0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "priv.h"
0025
0026 #include <subdev/gpio.h>
0027 #include <subdev/timer.h>
0028
0029 struct nvkm_fantog {
0030 struct nvkm_fan base;
0031 struct nvkm_alarm alarm;
0032 spinlock_t lock;
0033 u32 period_us;
0034 u32 percent;
0035 struct dcb_gpio_func func;
0036 };
0037
0038 static void
0039 nvkm_fantog_update(struct nvkm_fantog *fan, int percent)
0040 {
0041 struct nvkm_therm *therm = fan->base.parent;
0042 struct nvkm_device *device = therm->subdev.device;
0043 struct nvkm_timer *tmr = device->timer;
0044 struct nvkm_gpio *gpio = device->gpio;
0045 unsigned long flags;
0046 int duty;
0047
0048 spin_lock_irqsave(&fan->lock, flags);
0049 if (percent < 0)
0050 percent = fan->percent;
0051 fan->percent = percent;
0052
0053 duty = !nvkm_gpio_get(gpio, 0, DCB_GPIO_FAN, 0xff);
0054 nvkm_gpio_set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
0055
0056 if (percent != (duty * 100)) {
0057 u64 next_change = (percent * fan->period_us) / 100;
0058 if (!duty)
0059 next_change = fan->period_us - next_change;
0060 nvkm_timer_alarm(tmr, next_change * 1000, &fan->alarm);
0061 }
0062 spin_unlock_irqrestore(&fan->lock, flags);
0063 }
0064
0065 static void
0066 nvkm_fantog_alarm(struct nvkm_alarm *alarm)
0067 {
0068 struct nvkm_fantog *fan =
0069 container_of(alarm, struct nvkm_fantog, alarm);
0070 nvkm_fantog_update(fan, -1);
0071 }
0072
0073 static int
0074 nvkm_fantog_get(struct nvkm_therm *therm)
0075 {
0076 struct nvkm_fantog *fan = (void *)therm->fan;
0077 return fan->percent;
0078 }
0079
0080 static int
0081 nvkm_fantog_set(struct nvkm_therm *therm, int percent)
0082 {
0083 struct nvkm_fantog *fan = (void *)therm->fan;
0084 if (therm->func->pwm_ctrl)
0085 therm->func->pwm_ctrl(therm, fan->func.line, false);
0086 nvkm_fantog_update(fan, percent);
0087 return 0;
0088 }
0089
0090 int
0091 nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
0092 {
0093 struct nvkm_fantog *fan;
0094 int ret;
0095
0096 if (therm->func->pwm_ctrl) {
0097 ret = therm->func->pwm_ctrl(therm, func->line, false);
0098 if (ret)
0099 return ret;
0100 }
0101
0102 fan = kzalloc(sizeof(*fan), GFP_KERNEL);
0103 therm->fan = &fan->base;
0104 if (!fan)
0105 return -ENOMEM;
0106
0107 fan->base.type = "toggle";
0108 fan->base.get = nvkm_fantog_get;
0109 fan->base.set = nvkm_fantog_set;
0110 nvkm_alarm_init(&fan->alarm, nvkm_fantog_alarm);
0111 fan->period_us = 100000;
0112 fan->percent = 100;
0113 fan->func = *func;
0114 spin_lock_init(&fan->lock);
0115 return 0;
0116 }