1*cf3c1e67SAndrew Jeffery
2*cf3c1e67SAndrew Jeffery /*
3*cf3c1e67SAndrew Jeffery * Simple interface library for fan control operations
4*cf3c1e67SAndrew Jeffery * This file provides interface functions to support pwmtachtool.
5*cf3c1e67SAndrew Jeffery * Copyright (C) <2019> <American Megatrends International LLC>
6*cf3c1e67SAndrew Jeffery *
7*cf3c1e67SAndrew Jeffery */
8*cf3c1e67SAndrew Jeffery
9*cf3c1e67SAndrew Jeffery #include <stdio.h>
10*cf3c1e67SAndrew Jeffery #include <unistd.h>
11*cf3c1e67SAndrew Jeffery #include <sys/types.h>
12*cf3c1e67SAndrew Jeffery #include <sys/stat.h>
13*cf3c1e67SAndrew Jeffery #include <fcntl.h>
14*cf3c1e67SAndrew Jeffery #include <sys/ioctl.h>
15*cf3c1e67SAndrew Jeffery #include <errno.h>
16*cf3c1e67SAndrew Jeffery #include <string.h>
17*cf3c1e67SAndrew Jeffery #include "libpwmtach.h"
18*cf3c1e67SAndrew Jeffery #include "pwmtach_ioctl.h"
19*cf3c1e67SAndrew Jeffery #include "EINTR_wrappers.h"
20*cf3c1e67SAndrew Jeffery #include <stdlib.h>
21*cf3c1e67SAndrew Jeffery
select_sleep(time_t sec,suseconds_t usec)22*cf3c1e67SAndrew Jeffery void select_sleep(time_t sec,suseconds_t usec)
23*cf3c1e67SAndrew Jeffery {
24*cf3c1e67SAndrew Jeffery struct timeval tv;
25*cf3c1e67SAndrew Jeffery
26*cf3c1e67SAndrew Jeffery tv.tv_sec = sec;
27*cf3c1e67SAndrew Jeffery tv.tv_usec = usec;
28*cf3c1e67SAndrew Jeffery
29*cf3c1e67SAndrew Jeffery while(sigwrap_select(0, NULL, NULL, NULL, &tv) < 0);
30*cf3c1e67SAndrew Jeffery }
31*cf3c1e67SAndrew Jeffery
32*cf3c1e67SAndrew Jeffery //support acessing driver using sysfs device file
33*cf3c1e67SAndrew Jeffery static char DevNodeFileName[50];
34*cf3c1e67SAndrew Jeffery #define HWMON_DIR "/sys/class/hwmon"
35*cf3c1e67SAndrew Jeffery
36*cf3c1e67SAndrew Jeffery //build the pwm and tach access device node file name, and mapping pwm/tach number starting from 1.
37*cf3c1e67SAndrew Jeffery #define BUILD_PWM_NODE_NAME(buffer,DEV_ID,PWM_NUM) snprintf(buffer, sizeof(buffer), "%s%d%s%d", HWMON_DIR "/hwmon",DEV_ID, "/pwm", PWM_NUM+1)
38*cf3c1e67SAndrew Jeffery #define BUILD_TACH_NODE_NAME(buffer,DEV_ID,TACH_NUM) snprintf(buffer, sizeof(buffer), "%s%d%s%d%s", HWMON_DIR "/hwmon",DEV_ID, "/fan", TACH_NUM+1,"_input")
39*cf3c1e67SAndrew Jeffery #define BUILD_FAN_REG_NAME(buffer,DEV_ID,FAN_NUM) snprintf(buffer, sizeof(buffer), "%s%d%s%d%s", HWMON_DIR "/hwmon",DEV_ID, "/of_node/fan@", FAN_NUM,"/reg")
40*cf3c1e67SAndrew Jeffery
41*cf3c1e67SAndrew Jeffery //predefine FAN RPM range, must defined at some where for configuration.
42*cf3c1e67SAndrew Jeffery #define RPM_MAX 38600
43*cf3c1e67SAndrew Jeffery #define RPM_MIN 7500
44*cf3c1e67SAndrew Jeffery #define COUNTERRES_DEF 100
45*cf3c1e67SAndrew Jeffery
46*cf3c1e67SAndrew Jeffery /* Check hwmon if exist or not */
pwmtach_directory_check(void)47*cf3c1e67SAndrew Jeffery static int pwmtach_directory_check(void)
48*cf3c1e67SAndrew Jeffery {
49*cf3c1e67SAndrew Jeffery int retval = 0;
50*cf3c1e67SAndrew Jeffery struct stat sb;
51*cf3c1e67SAndrew Jeffery if (!(stat("/sys/class/hwmon", &sb) == 0 && S_ISDIR(sb.st_mode)))
52*cf3c1e67SAndrew Jeffery {
53*cf3c1e67SAndrew Jeffery printf("\"/sys/class/hwmon\" not exist!\n");
54*cf3c1e67SAndrew Jeffery retval = -1;
55*cf3c1e67SAndrew Jeffery }
56*cf3c1e67SAndrew Jeffery return retval;
57*cf3c1e67SAndrew Jeffery }
58*cf3c1e67SAndrew Jeffery //Notice: dutycycle_value is one byte (0-255)
SET_PWM_DUTYCYCLE_VALUE(pwmtach_ioctl_data * ppwmtach_arg)59*cf3c1e67SAndrew Jeffery static int SET_PWM_DUTYCYCLE_VALUE ( pwmtach_ioctl_data *ppwmtach_arg )
60*cf3c1e67SAndrew Jeffery {
61*cf3c1e67SAndrew Jeffery int retval = 0;
62*cf3c1e67SAndrew Jeffery unsigned char dutycycle_value;
63*cf3c1e67SAndrew Jeffery int fd;
64*cf3c1e67SAndrew Jeffery char duty_num[5];
65*cf3c1e67SAndrew Jeffery
66*cf3c1e67SAndrew Jeffery retval = pwmtach_directory_check();
67*cf3c1e67SAndrew Jeffery if(retval != 0)
68*cf3c1e67SAndrew Jeffery {
69*cf3c1e67SAndrew Jeffery return retval;
70*cf3c1e67SAndrew Jeffery }
71*cf3c1e67SAndrew Jeffery
72*cf3c1e67SAndrew Jeffery dutycycle_value = ppwmtach_arg->dutycycle;
73*cf3c1e67SAndrew Jeffery BUILD_PWM_NODE_NAME(DevNodeFileName,ppwmtach_arg->dev_id,ppwmtach_arg->pwmnumber);
74*cf3c1e67SAndrew Jeffery retval = access(DevNodeFileName,F_OK);
75*cf3c1e67SAndrew Jeffery if(retval != 0)
76*cf3c1e67SAndrew Jeffery {
77*cf3c1e67SAndrew Jeffery return retval;
78*cf3c1e67SAndrew Jeffery }
79*cf3c1e67SAndrew Jeffery
80*cf3c1e67SAndrew Jeffery fd = sigwrap_open(DevNodeFileName, O_WRONLY);
81*cf3c1e67SAndrew Jeffery if (fd < 0) {
82*cf3c1e67SAndrew Jeffery return fd;
83*cf3c1e67SAndrew Jeffery }
84*cf3c1e67SAndrew Jeffery
85*cf3c1e67SAndrew Jeffery snprintf(duty_num,5, "%d", dutycycle_value);
86*cf3c1e67SAndrew Jeffery
87*cf3c1e67SAndrew Jeffery if ( write(fd, duty_num, strlen (duty_num)) != (ssize_t )strlen(duty_num)){
88*cf3c1e67SAndrew Jeffery printf("%s: Error write dutycycle value %d to pwm %d\n",__FUNCTION__,dutycycle_value,ppwmtach_arg->pwmnumber);
89*cf3c1e67SAndrew Jeffery retval = -1;
90*cf3c1e67SAndrew Jeffery }
91*cf3c1e67SAndrew Jeffery (void)sigwrap_close(fd);
92*cf3c1e67SAndrew Jeffery
93*cf3c1e67SAndrew Jeffery return retval;
94*cf3c1e67SAndrew Jeffery }
95*cf3c1e67SAndrew Jeffery
96*cf3c1e67SAndrew Jeffery //Notice: dutycycle_percentage value should be between 1 to 99.
SET_PWM_DUTYCYCLE(pwmtach_ioctl_data * ppwmtach_arg)97*cf3c1e67SAndrew Jeffery static int SET_PWM_DUTYCYCLE ( pwmtach_ioctl_data *ppwmtach_arg)
98*cf3c1e67SAndrew Jeffery {
99*cf3c1e67SAndrew Jeffery int retval = 0;
100*cf3c1e67SAndrew Jeffery unsigned char dutycycle_value;
101*cf3c1e67SAndrew Jeffery
102*cf3c1e67SAndrew Jeffery if(ppwmtach_arg->dutycycle > 100)
103*cf3c1e67SAndrew Jeffery {
104*cf3c1e67SAndrew Jeffery return -1;
105*cf3c1e67SAndrew Jeffery }
106*cf3c1e67SAndrew Jeffery
107*cf3c1e67SAndrew Jeffery dutycycle_value = (ppwmtach_arg->dutycycle*255)/100;
108*cf3c1e67SAndrew Jeffery ppwmtach_arg->dutycycle = dutycycle_value;
109*cf3c1e67SAndrew Jeffery retval = SET_PWM_DUTYCYCLE_VALUE(ppwmtach_arg);
110*cf3c1e67SAndrew Jeffery return retval;
111*cf3c1e67SAndrew Jeffery }
112*cf3c1e67SAndrew Jeffery
GET_PWM_DUTYCYCLE(pwmtach_ioctl_data * ppwmtach_arg)113*cf3c1e67SAndrew Jeffery static int GET_PWM_DUTYCYCLE ( pwmtach_ioctl_data *ppwmtach_arg )
114*cf3c1e67SAndrew Jeffery {
115*cf3c1e67SAndrew Jeffery int retval = 0;
116*cf3c1e67SAndrew Jeffery int fd;
117*cf3c1e67SAndrew Jeffery char duty_num[5];
118*cf3c1e67SAndrew Jeffery
119*cf3c1e67SAndrew Jeffery retval = pwmtach_directory_check();
120*cf3c1e67SAndrew Jeffery if(retval != 0)
121*cf3c1e67SAndrew Jeffery {//printf("%s,error 0\n",__FUNCTION__);
122*cf3c1e67SAndrew Jeffery return retval;
123*cf3c1e67SAndrew Jeffery }
124*cf3c1e67SAndrew Jeffery
125*cf3c1e67SAndrew Jeffery BUILD_PWM_NODE_NAME(DevNodeFileName,ppwmtach_arg->dev_id,ppwmtach_arg->pwmnumber);
126*cf3c1e67SAndrew Jeffery retval = access(DevNodeFileName,F_OK);
127*cf3c1e67SAndrew Jeffery if(retval != 0)
128*cf3c1e67SAndrew Jeffery {printf("%s,error 2,%s not exist\n",__FUNCTION__,DevNodeFileName);
129*cf3c1e67SAndrew Jeffery return retval;
130*cf3c1e67SAndrew Jeffery }
131*cf3c1e67SAndrew Jeffery fd = sigwrap_open(DevNodeFileName, O_RDONLY);
132*cf3c1e67SAndrew Jeffery if (fd < 0) {printf("%s,error 3\n",__FUNCTION__);
133*cf3c1e67SAndrew Jeffery return fd;
134*cf3c1e67SAndrew Jeffery }
135*cf3c1e67SAndrew Jeffery read(fd, duty_num, 5);
136*cf3c1e67SAndrew Jeffery ppwmtach_arg->dutycycle = atoi(duty_num);
137*cf3c1e67SAndrew Jeffery printf("%s:dutycycle value %d to pwm %d\n",__FUNCTION__,ppwmtach_arg->dutycycle,ppwmtach_arg->pwmnumber);
138*cf3c1e67SAndrew Jeffery (void)sigwrap_close(fd);
139*cf3c1e67SAndrew Jeffery
140*cf3c1e67SAndrew Jeffery return retval;
141*cf3c1e67SAndrew Jeffery }
GET_TACH_SPEED(pwmtach_ioctl_data * ppwmtach_arg)142*cf3c1e67SAndrew Jeffery int GET_TACH_SPEED (pwmtach_ioctl_data *ppwmtach_arg )
143*cf3c1e67SAndrew Jeffery {
144*cf3c1e67SAndrew Jeffery int retval = 0;
145*cf3c1e67SAndrew Jeffery int fd;
146*cf3c1e67SAndrew Jeffery char data[6];
147*cf3c1e67SAndrew Jeffery
148*cf3c1e67SAndrew Jeffery retval = pwmtach_directory_check();
149*cf3c1e67SAndrew Jeffery if(retval != 0)
150*cf3c1e67SAndrew Jeffery {printf("%s,error 0\n",__FUNCTION__);
151*cf3c1e67SAndrew Jeffery return retval;
152*cf3c1e67SAndrew Jeffery }
153*cf3c1e67SAndrew Jeffery BUILD_TACH_NODE_NAME(DevNodeFileName,ppwmtach_arg->dev_id,ppwmtach_arg->tachnumber);
154*cf3c1e67SAndrew Jeffery retval = access(DevNodeFileName,F_OK);
155*cf3c1e67SAndrew Jeffery if(retval != 0)
156*cf3c1e67SAndrew Jeffery {printf("%s,error 2,%s not exist\n",__FUNCTION__,DevNodeFileName);
157*cf3c1e67SAndrew Jeffery return retval;
158*cf3c1e67SAndrew Jeffery }
159*cf3c1e67SAndrew Jeffery
160*cf3c1e67SAndrew Jeffery fd = sigwrap_open(DevNodeFileName, O_RDONLY);
161*cf3c1e67SAndrew Jeffery if (fd < 0) {printf("%s,error 3\n",__FUNCTION__);
162*cf3c1e67SAndrew Jeffery return fd;
163*cf3c1e67SAndrew Jeffery }
164*cf3c1e67SAndrew Jeffery memset(data, 0, 6);
165*cf3c1e67SAndrew Jeffery read(fd, data, 6);
166*cf3c1e67SAndrew Jeffery ppwmtach_arg->rpmvalue = atoi(data);
167*cf3c1e67SAndrew Jeffery (void)sigwrap_close(fd);
168*cf3c1e67SAndrew Jeffery printf("%s:rpm value %d\n",__FUNCTION__,ppwmtach_arg->rpmvalue);
169*cf3c1e67SAndrew Jeffery return retval;
170*cf3c1e67SAndrew Jeffery }
171*cf3c1e67SAndrew Jeffery //mapping function of fan to tach
172*cf3c1e67SAndrew Jeffery //using direct mapping as default
173*cf3c1e67SAndrew Jeffery #define GET_TACH_NUMBER(FAN_NUMBER) FAN_NUMBER
174*cf3c1e67SAndrew Jeffery //mapping fan number to pwm number
175*cf3c1e67SAndrew Jeffery //using information in fan@number reg item, to look up the pwm index
GET_PWM_NUMBER(pwmtach_ioctl_data * ppwmtach_arg)176*cf3c1e67SAndrew Jeffery static int GET_PWM_NUMBER(pwmtach_ioctl_data *ppwmtach_arg)
177*cf3c1e67SAndrew Jeffery {
178*cf3c1e67SAndrew Jeffery int retval = 0;
179*cf3c1e67SAndrew Jeffery int fd;
180*cf3c1e67SAndrew Jeffery int reg_val = 0;
181*cf3c1e67SAndrew Jeffery
182*cf3c1e67SAndrew Jeffery retval = pwmtach_directory_check();
183*cf3c1e67SAndrew Jeffery if(retval != 0)
184*cf3c1e67SAndrew Jeffery {printf("%s,error 0\n",__FUNCTION__);
185*cf3c1e67SAndrew Jeffery return retval;
186*cf3c1e67SAndrew Jeffery }
187*cf3c1e67SAndrew Jeffery BUILD_FAN_REG_NAME(DevNodeFileName,ppwmtach_arg->dev_id,ppwmtach_arg->fannumber);
188*cf3c1e67SAndrew Jeffery retval = access(DevNodeFileName,F_OK);
189*cf3c1e67SAndrew Jeffery if(retval != 0)
190*cf3c1e67SAndrew Jeffery {printf("%s,error 2,%s not exist\n",__FUNCTION__,DevNodeFileName);
191*cf3c1e67SAndrew Jeffery return retval;
192*cf3c1e67SAndrew Jeffery }
193*cf3c1e67SAndrew Jeffery
194*cf3c1e67SAndrew Jeffery fd = sigwrap_open(DevNodeFileName, O_RDONLY);
195*cf3c1e67SAndrew Jeffery if (fd < 0) {printf("%s,error 3\n",__FUNCTION__);
196*cf3c1e67SAndrew Jeffery return fd;
197*cf3c1e67SAndrew Jeffery }
198*cf3c1e67SAndrew Jeffery read(fd, ®_val, sizeof(int));
199*cf3c1e67SAndrew Jeffery if(reg_val < 0)
200*cf3c1e67SAndrew Jeffery {
201*cf3c1e67SAndrew Jeffery retval = -1;
202*cf3c1e67SAndrew Jeffery }else
203*cf3c1e67SAndrew Jeffery {
204*cf3c1e67SAndrew Jeffery retval = reg_val >> 24; //get the highest byte
205*cf3c1e67SAndrew Jeffery printf("%s:fan %d, pwm %d, val 0x%X\n",__FUNCTION__,ppwmtach_arg->fannumber,retval,reg_val);
206*cf3c1e67SAndrew Jeffery printf("%s\n",DevNodeFileName);
207*cf3c1e67SAndrew Jeffery }
208*cf3c1e67SAndrew Jeffery (void)sigwrap_close(fd);
209*cf3c1e67SAndrew Jeffery // printf("%s:rpm value %d\n",__FUNCTION__,ppwmtach_arg->rpmvalue);
210*cf3c1e67SAndrew Jeffery return retval;
211*cf3c1e67SAndrew Jeffery }
pwmtach_action(pwmtach_ioctl_data * argp,int command)212*cf3c1e67SAndrew Jeffery static int pwmtach_action( pwmtach_ioctl_data* argp, int command )
213*cf3c1e67SAndrew Jeffery {
214*cf3c1e67SAndrew Jeffery int retval = 0;
215*cf3c1e67SAndrew Jeffery // printf("%s, Command 0x%X:Dev:%d,Pwm:0x%X,Fan:0x%x,Tach:0x%X\n",__FUNCTION__,command,argp->dev_id,argp->pwmnumber,argp->fannumber,argp->tachnumber);
216*cf3c1e67SAndrew Jeffery switch(command)
217*cf3c1e67SAndrew Jeffery {
218*cf3c1e67SAndrew Jeffery case SET_DUTY_CYCLE_BY_PWM_CHANNEL:
219*cf3c1e67SAndrew Jeffery retval = SET_PWM_DUTYCYCLE(argp);
220*cf3c1e67SAndrew Jeffery break;
221*cf3c1e67SAndrew Jeffery case SET_DUTY_CYCLE_VALUE_BY_PWM_CHANNEL:
222*cf3c1e67SAndrew Jeffery case SET_DUTY_CYCLE:
223*cf3c1e67SAndrew Jeffery retval = SET_PWM_DUTYCYCLE_VALUE(argp);
224*cf3c1e67SAndrew Jeffery break;
225*cf3c1e67SAndrew Jeffery case GET_TACH_VALUE_BY_TACH_CHANNEL:
226*cf3c1e67SAndrew Jeffery retval = GET_TACH_SPEED(argp);
227*cf3c1e67SAndrew Jeffery break;
228*cf3c1e67SAndrew Jeffery case GET_TACH_VALUE: //used to get fan speed
229*cf3c1e67SAndrew Jeffery argp->tachnumber = GET_TACH_NUMBER(argp->fannumber);
230*cf3c1e67SAndrew Jeffery retval = GET_TACH_SPEED(argp);
231*cf3c1e67SAndrew Jeffery break;
232*cf3c1e67SAndrew Jeffery case GET_DUTY_CYCLE:
233*cf3c1e67SAndrew Jeffery retval = GET_PWM_DUTYCYCLE(argp);
234*cf3c1e67SAndrew Jeffery break;
235*cf3c1e67SAndrew Jeffery case GET_FAN_RPM_RANGE:
236*cf3c1e67SAndrew Jeffery argp->max_rpm = RPM_MAX;
237*cf3c1e67SAndrew Jeffery argp->min_rpm = RPM_MIN;
238*cf3c1e67SAndrew Jeffery break;
239*cf3c1e67SAndrew Jeffery case INIT_PWMTACH: //assume that init complete
240*cf3c1e67SAndrew Jeffery argp->pwmnumber = GET_PWM_NUMBER(argp);; //since we don't have the fan to pwm mapping, just using direct map for workarround.
241*cf3c1e67SAndrew Jeffery argp->counterresvalue = COUNTERRES_DEF; //since driver don't support COUNTERRES, just using default value for workarround.
242*cf3c1e67SAndrew Jeffery retval = GET_PWM_DUTYCYCLE(argp);
243*cf3c1e67SAndrew Jeffery break;
244*cf3c1e67SAndrew Jeffery case END_OF_FUNC_TABLE:
245*cf3c1e67SAndrew Jeffery default:
246*cf3c1e67SAndrew Jeffery printf("%s, Command 0x%X not support!\n",__FUNCTION__,command);
247*cf3c1e67SAndrew Jeffery retval = -1;
248*cf3c1e67SAndrew Jeffery }
249*cf3c1e67SAndrew Jeffery return( retval );
250*cf3c1e67SAndrew Jeffery }
251*cf3c1e67SAndrew Jeffery
get_tach_speed(unsigned int dev_id,unsigned char tach_number,unsigned int * rpm_value)252*cf3c1e67SAndrew Jeffery int get_tach_speed ( unsigned int dev_id, unsigned char tach_number, unsigned int *rpm_value )
253*cf3c1e67SAndrew Jeffery {
254*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
255*cf3c1e67SAndrew Jeffery int retval = 0;
256*cf3c1e67SAndrew Jeffery
257*cf3c1e67SAndrew Jeffery pwmtach_arg.dev_id = dev_id;
258*cf3c1e67SAndrew Jeffery pwmtach_arg.tachnumber = tach_number;
259*cf3c1e67SAndrew Jeffery retval = pwmtach_action( &pwmtach_arg, GET_TACH_VALUE_BY_TACH_CHANNEL);
260*cf3c1e67SAndrew Jeffery if(retval != -1)
261*cf3c1e67SAndrew Jeffery *rpm_value = pwmtach_arg.rpmvalue;
262*cf3c1e67SAndrew Jeffery return retval;
263*cf3c1e67SAndrew Jeffery }
264*cf3c1e67SAndrew Jeffery
265*cf3c1e67SAndrew Jeffery //Notice: dutycycle_percentage value should be between 1 to 99.
set_pwm_dutycycle(unsigned int dev_id,unsigned char pwm_number,unsigned char dutycycle_percentage)266*cf3c1e67SAndrew Jeffery int set_pwm_dutycycle ( unsigned int dev_id, unsigned char pwm_number, unsigned char dutycycle_percentage )
267*cf3c1e67SAndrew Jeffery {
268*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
269*cf3c1e67SAndrew Jeffery int retval = 0;
270*cf3c1e67SAndrew Jeffery
271*cf3c1e67SAndrew Jeffery pwmtach_arg.dev_id = dev_id;
272*cf3c1e67SAndrew Jeffery pwmtach_arg.pwmnumber = pwm_number;
273*cf3c1e67SAndrew Jeffery pwmtach_arg.dutycycle= dutycycle_percentage;
274*cf3c1e67SAndrew Jeffery retval = pwmtach_action( &pwmtach_arg, SET_DUTY_CYCLE_BY_PWM_CHANNEL);
275*cf3c1e67SAndrew Jeffery
276*cf3c1e67SAndrew Jeffery return retval;
277*cf3c1e67SAndrew Jeffery }
278*cf3c1e67SAndrew Jeffery
279*cf3c1e67SAndrew Jeffery //Notice: dutycycle_value is one byte (0-255)
set_pwm_dutycycle_value(unsigned int dev_id,unsigned char pwm_number,unsigned char dutycycle_value)280*cf3c1e67SAndrew Jeffery int set_pwm_dutycycle_value ( unsigned int dev_id, unsigned char pwm_number, unsigned char dutycycle_value )
281*cf3c1e67SAndrew Jeffery {
282*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
283*cf3c1e67SAndrew Jeffery int retval = 0;
284*cf3c1e67SAndrew Jeffery
285*cf3c1e67SAndrew Jeffery pwmtach_arg.dev_id = dev_id;
286*cf3c1e67SAndrew Jeffery pwmtach_arg.pwmnumber = pwm_number;
287*cf3c1e67SAndrew Jeffery pwmtach_arg.dutycycle= dutycycle_value;
288*cf3c1e67SAndrew Jeffery retval = pwmtach_action( &pwmtach_arg, SET_DUTY_CYCLE_VALUE_BY_PWM_CHANNEL);
289*cf3c1e67SAndrew Jeffery
290*cf3c1e67SAndrew Jeffery return retval;
291*cf3c1e67SAndrew Jeffery }
292*cf3c1e67SAndrew Jeffery
get_pwm_dutycycle(unsigned int dev_id,unsigned char pwm_number,unsigned char * dutycycle_percentage)293*cf3c1e67SAndrew Jeffery int get_pwm_dutycycle ( unsigned int dev_id, unsigned char pwm_number, unsigned char *dutycycle_percentage )
294*cf3c1e67SAndrew Jeffery {
295*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
296*cf3c1e67SAndrew Jeffery int retval = 0;
297*cf3c1e67SAndrew Jeffery
298*cf3c1e67SAndrew Jeffery pwmtach_arg.dev_id = dev_id;
299*cf3c1e67SAndrew Jeffery pwmtach_arg.pwmnumber = pwm_number;
300*cf3c1e67SAndrew Jeffery retval = pwmtach_action(&pwmtach_arg, GET_DUTY_CYCLE);
301*cf3c1e67SAndrew Jeffery if(retval != -1)
302*cf3c1e67SAndrew Jeffery *dutycycle_percentage = pwmtach_arg.dutycycle;
303*cf3c1e67SAndrew Jeffery return retval;
304*cf3c1e67SAndrew Jeffery
305*cf3c1e67SAndrew Jeffery }
306*cf3c1e67SAndrew Jeffery
set_fan_speed(unsigned int dev_id,unsigned char fan_number,unsigned int rpm_value)307*cf3c1e67SAndrew Jeffery int set_fan_speed ( unsigned int dev_id, unsigned char fan_number, unsigned int rpm_value )
308*cf3c1e67SAndrew Jeffery {
309*cf3c1e67SAndrew Jeffery int retval = 0;
310*cf3c1e67SAndrew Jeffery unsigned int retries = 20;
311*cf3c1e67SAndrew Jeffery unsigned char firsttime = 1;
312*cf3c1e67SAndrew Jeffery unsigned char duty_cycle_increasing = 0;
313*cf3c1e67SAndrew Jeffery unsigned char reached90percent = 0;
314*cf3c1e67SAndrew Jeffery unsigned char reached5percent = 0;
315*cf3c1e67SAndrew Jeffery unsigned long desiredrpm = rpm_value;
316*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
317*cf3c1e67SAndrew Jeffery pwmtach_data_t* indata = (pwmtach_data_t*) &pwmtach_arg;
318*cf3c1e67SAndrew Jeffery
319*cf3c1e67SAndrew Jeffery indata->dev_id = dev_id;
320*cf3c1e67SAndrew Jeffery indata->fannumber = fan_number;
321*cf3c1e67SAndrew Jeffery indata->rpmvalue = rpm_value;
322*cf3c1e67SAndrew Jeffery indata->counterresvalue = 0;
323*cf3c1e67SAndrew Jeffery indata->dutycycle = 0;
324*cf3c1e67SAndrew Jeffery indata->prevdutycycle = 0;
325*cf3c1e67SAndrew Jeffery
326*cf3c1e67SAndrew Jeffery retval = pwmtach_action( indata, GET_FAN_RPM_RANGE);
327*cf3c1e67SAndrew Jeffery if ((rpm_value < indata->min_rpm) || (rpm_value > indata->max_rpm))
328*cf3c1e67SAndrew Jeffery {
329*cf3c1e67SAndrew Jeffery printf("Out of range Fan Speed value for fan.\n");
330*cf3c1e67SAndrew Jeffery return -1;
331*cf3c1e67SAndrew Jeffery }
332*cf3c1e67SAndrew Jeffery retval = pwmtach_action ( indata, INIT_PWMTACH );
333*cf3c1e67SAndrew Jeffery
334*cf3c1e67SAndrew Jeffery while (retries--)
335*cf3c1e67SAndrew Jeffery {
336*cf3c1e67SAndrew Jeffery /* Wait for 1 seconds */
337*cf3c1e67SAndrew Jeffery select_sleep(0,1*1000*1000);
338*cf3c1e67SAndrew Jeffery if ((retval = pwmtach_action( indata, GET_TACH_VALUE )) != 0)
339*cf3c1e67SAndrew Jeffery {
340*cf3c1e67SAndrew Jeffery indata->dutycycle = indata->prevdutycycle;
341*cf3c1e67SAndrew Jeffery retval = pwmtach_action( indata, SET_DUTY_CYCLE);
342*cf3c1e67SAndrew Jeffery return -1;
343*cf3c1e67SAndrew Jeffery }
344*cf3c1e67SAndrew Jeffery else
345*cf3c1e67SAndrew Jeffery {
346*cf3c1e67SAndrew Jeffery indata->prevdutycycle = indata->dutycycle;
347*cf3c1e67SAndrew Jeffery if (indata->rpmvalue > (desiredrpm + 50))
348*cf3c1e67SAndrew Jeffery {
349*cf3c1e67SAndrew Jeffery if (indata->dutycycle <= ((indata->counterresvalue*10)/100))
350*cf3c1e67SAndrew Jeffery {
351*cf3c1e67SAndrew Jeffery if (reached5percent == 1)
352*cf3c1e67SAndrew Jeffery {
353*cf3c1e67SAndrew Jeffery printf("\nSpeed is set to minimum possible speed of %d RPM.\n",indata->rpmvalue);
354*cf3c1e67SAndrew Jeffery break;
355*cf3c1e67SAndrew Jeffery }
356*cf3c1e67SAndrew Jeffery reached5percent = 1;
357*cf3c1e67SAndrew Jeffery }
358*cf3c1e67SAndrew Jeffery else
359*cf3c1e67SAndrew Jeffery {
360*cf3c1e67SAndrew Jeffery indata->dutycycle -= ((5 * indata->counterresvalue)/100);
361*cf3c1e67SAndrew Jeffery }
362*cf3c1e67SAndrew Jeffery }
363*cf3c1e67SAndrew Jeffery else if (indata->rpmvalue < (desiredrpm - 50))
364*cf3c1e67SAndrew Jeffery {
365*cf3c1e67SAndrew Jeffery if (indata->dutycycle >= indata->counterresvalue)
366*cf3c1e67SAndrew Jeffery {
367*cf3c1e67SAndrew Jeffery if (reached90percent == 1)
368*cf3c1e67SAndrew Jeffery {
369*cf3c1e67SAndrew Jeffery printf("\nSpeed is set to maximum possible speed of %d RPM.\n",indata->rpmvalue);
370*cf3c1e67SAndrew Jeffery break;
371*cf3c1e67SAndrew Jeffery }
372*cf3c1e67SAndrew Jeffery reached90percent = 1;
373*cf3c1e67SAndrew Jeffery }
374*cf3c1e67SAndrew Jeffery else
375*cf3c1e67SAndrew Jeffery {
376*cf3c1e67SAndrew Jeffery indata->dutycycle += ((5 * indata->counterresvalue)/100);
377*cf3c1e67SAndrew Jeffery }
378*cf3c1e67SAndrew Jeffery }
379*cf3c1e67SAndrew Jeffery else
380*cf3c1e67SAndrew Jeffery {
381*cf3c1e67SAndrew Jeffery break;
382*cf3c1e67SAndrew Jeffery }
383*cf3c1e67SAndrew Jeffery
384*cf3c1e67SAndrew Jeffery retval = pwmtach_action (indata, SET_DUTY_CYCLE);
385*cf3c1e67SAndrew Jeffery printf("After update: dutycycle=%d, rpmvalue=%d\n", indata->dutycycle, indata->rpmvalue);
386*cf3c1e67SAndrew Jeffery
387*cf3c1e67SAndrew Jeffery if(indata->prevdutycycle < indata->dutycycle)
388*cf3c1e67SAndrew Jeffery { /* Duty Cycle increasing */
389*cf3c1e67SAndrew Jeffery if ((firsttime == 0) && (duty_cycle_increasing == 0))
390*cf3c1e67SAndrew Jeffery {
391*cf3c1e67SAndrew Jeffery indata->dutycycle = indata->prevdutycycle;
392*cf3c1e67SAndrew Jeffery retval = pwmtach_action( indata, SET_DUTY_CYCLE);
393*cf3c1e67SAndrew Jeffery printf("\n");
394*cf3c1e67SAndrew Jeffery return 0;
395*cf3c1e67SAndrew Jeffery }
396*cf3c1e67SAndrew Jeffery duty_cycle_increasing = 1;
397*cf3c1e67SAndrew Jeffery }
398*cf3c1e67SAndrew Jeffery else
399*cf3c1e67SAndrew Jeffery { /* Duty Cycle decreasing */
400*cf3c1e67SAndrew Jeffery if ((firsttime == 0) && (duty_cycle_increasing == 1))
401*cf3c1e67SAndrew Jeffery {
402*cf3c1e67SAndrew Jeffery indata->dutycycle = indata->prevdutycycle;
403*cf3c1e67SAndrew Jeffery retval = pwmtach_action( indata, SET_DUTY_CYCLE);
404*cf3c1e67SAndrew Jeffery printf("\n");
405*cf3c1e67SAndrew Jeffery return 0;
406*cf3c1e67SAndrew Jeffery }
407*cf3c1e67SAndrew Jeffery duty_cycle_increasing = 0;
408*cf3c1e67SAndrew Jeffery }
409*cf3c1e67SAndrew Jeffery if (firsttime == 1)
410*cf3c1e67SAndrew Jeffery firsttime = 0;
411*cf3c1e67SAndrew Jeffery }
412*cf3c1e67SAndrew Jeffery printf("retry %d : dt=%d, ps=%d, cr=%d\n", retries, indata->dutycycle, indata->prescalervalue, indata->counterresvalue);
413*cf3c1e67SAndrew Jeffery }
414*cf3c1e67SAndrew Jeffery return 0;
415*cf3c1e67SAndrew Jeffery
416*cf3c1e67SAndrew Jeffery }
417*cf3c1e67SAndrew Jeffery
get_fan_speed(unsigned int dev_id,unsigned char fan_number,unsigned int * rpm_value)418*cf3c1e67SAndrew Jeffery int get_fan_speed ( unsigned int dev_id, unsigned char fan_number, unsigned int *rpm_value )
419*cf3c1e67SAndrew Jeffery {
420*cf3c1e67SAndrew Jeffery pwmtach_ioctl_data pwmtach_arg;
421*cf3c1e67SAndrew Jeffery int retval = 0;
422*cf3c1e67SAndrew Jeffery
423*cf3c1e67SAndrew Jeffery pwmtach_arg.dev_id = dev_id;
424*cf3c1e67SAndrew Jeffery pwmtach_arg.fannumber = fan_number;
425*cf3c1e67SAndrew Jeffery retval = pwmtach_action( &pwmtach_arg, GET_TACH_VALUE );
426*cf3c1e67SAndrew Jeffery if(retval != -1)
427*cf3c1e67SAndrew Jeffery *rpm_value = pwmtach_arg.rpmvalue;
428*cf3c1e67SAndrew Jeffery return retval;
429*cf3c1e67SAndrew Jeffery }
430