Linux 6.9-rc5
[sfrench/cifs-2.6.git] / drivers / hwmon / ftsteutates.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Support for the FTS Systemmonitoring Chip "Teutates"
4  *
5  * Copyright (C) 2016 Fujitsu Technology Solutions GmbH,
6  *                Thilo Cestonaro <thilo.cestonaro@ts.fujitsu.com>
7  */
8 #include <linux/err.h>
9 #include <linux/hwmon.h>
10 #include <linux/i2c.h>
11 #include <linux/init.h>
12 #include <linux/jiffies.h>
13 #include <linux/math.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/slab.h>
17 #include <linux/watchdog.h>
18
19 #define FTS_DEVICE_ID_REG               0x0000
20 #define FTS_DEVICE_REVISION_REG         0x0001
21 #define FTS_DEVICE_STATUS_REG           0x0004
22 #define FTS_SATELLITE_STATUS_REG        0x0005
23 #define FTS_EVENT_STATUS_REG            0x0006
24 #define FTS_GLOBAL_CONTROL_REG          0x0007
25
26 #define FTS_DEVICE_DETECT_REG_1         0x0C
27 #define FTS_DEVICE_DETECT_REG_2         0x0D
28 #define FTS_DEVICE_DETECT_REG_3         0x0E
29
30 #define FTS_SENSOR_EVENT_REG            0x0010
31
32 #define FTS_FAN_EVENT_REG               0x0014
33 #define FTS_FAN_PRESENT_REG             0x0015
34
35 #define FTS_POWER_ON_TIME_COUNTER_A     0x007A
36 #define FTS_POWER_ON_TIME_COUNTER_B     0x007B
37 #define FTS_POWER_ON_TIME_COUNTER_C     0x007C
38
39 #define FTS_PAGE_SELECT_REG             0x007F
40
41 #define FTS_WATCHDOG_TIME_PRESET        0x000B
42 #define FTS_WATCHDOG_CONTROL            0x5081
43
44 #define FTS_NO_FAN_SENSORS              0x08
45 #define FTS_NO_TEMP_SENSORS             0x10
46 #define FTS_NO_VOLT_SENSORS             0x04
47
48 #define FTS_FAN_SOURCE_INVALID          0xff
49
50 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
51
52 static const struct i2c_device_id fts_id[] = {
53         { "ftsteutates", 0 },
54         { }
55 };
56 MODULE_DEVICE_TABLE(i2c, fts_id);
57
58 enum WATCHDOG_RESOLUTION {
59         seconds = 1,
60         minutes = 60
61 };
62
63 struct fts_data {
64         struct i2c_client *client;
65         /* update sensor data lock */
66         struct mutex update_lock;
67         /* read/write register lock */
68         struct mutex access_lock;
69         unsigned long last_updated; /* in jiffies */
70         struct watchdog_device wdd;
71         enum WATCHDOG_RESOLUTION resolution;
72         bool valid; /* false until following fields are valid */
73
74         u8 volt[FTS_NO_VOLT_SENSORS];
75
76         u8 temp_input[FTS_NO_TEMP_SENSORS];
77         u8 temp_alarm;
78
79         u8 fan_present;
80         u8 fan_input[FTS_NO_FAN_SENSORS]; /* in rps */
81         u8 fan_source[FTS_NO_FAN_SENSORS];
82         u8 fan_alarm;
83 };
84
85 #define FTS_REG_FAN_INPUT(idx) ((idx) + 0x20)
86 #define FTS_REG_FAN_SOURCE(idx) ((idx) + 0x30)
87 #define FTS_REG_FAN_CONTROL(idx) (((idx) << 16) + 0x4881)
88
89 #define FTS_REG_TEMP_INPUT(idx) ((idx) + 0x40)
90 #define FTS_REG_TEMP_CONTROL(idx) (((idx) << 16) + 0x0681)
91
92 #define FTS_REG_VOLT(idx) ((idx) + 0x18)
93
94 /*****************************************************************************/
95 /* I2C Helper functions                                                      */
96 /*****************************************************************************/
97 static int fts_read_byte(struct i2c_client *client, unsigned short reg)
98 {
99         int ret;
100         unsigned char page = reg >> 8;
101         struct fts_data *data = dev_get_drvdata(&client->dev);
102
103         mutex_lock(&data->access_lock);
104
105         dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
106         ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
107         if (ret < 0)
108                 goto error;
109
110         reg &= 0xFF;
111         ret = i2c_smbus_read_byte_data(client, reg);
112         dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret);
113
114 error:
115         mutex_unlock(&data->access_lock);
116         return ret;
117 }
118
119 static int fts_write_byte(struct i2c_client *client, unsigned short reg,
120                           unsigned char value)
121 {
122         int ret;
123         unsigned char page = reg >> 8;
124         struct fts_data *data = dev_get_drvdata(&client->dev);
125
126         mutex_lock(&data->access_lock);
127
128         dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
129         ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
130         if (ret < 0)
131                 goto error;
132
133         reg &= 0xFF;
134         dev_dbg(&client->dev,
135                 "write - reg: 0x%.02x: val: 0x%.02x\n", reg, value);
136         ret = i2c_smbus_write_byte_data(client, reg, value);
137
138 error:
139         mutex_unlock(&data->access_lock);
140         return ret;
141 }
142
143 /*****************************************************************************/
144 /* Data Updater Helper function                                              */
145 /*****************************************************************************/
146 static int fts_update_device(struct fts_data *data)
147 {
148         int i;
149         int err = 0;
150
151         mutex_lock(&data->update_lock);
152         if (!time_after(jiffies, data->last_updated + 2 * HZ) && data->valid)
153                 goto exit;
154
155         err = fts_read_byte(data->client, FTS_DEVICE_STATUS_REG);
156         if (err < 0)
157                 goto exit;
158
159         data->valid = !!(err & 0x02); /* Data not ready yet */
160         if (unlikely(!data->valid)) {
161                 err = -EAGAIN;
162                 goto exit;
163         }
164
165         err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG);
166         if (err < 0)
167                 goto exit;
168         data->fan_present = err;
169
170         err = fts_read_byte(data->client, FTS_FAN_EVENT_REG);
171         if (err < 0)
172                 goto exit;
173         data->fan_alarm = err;
174
175         for (i = 0; i < FTS_NO_FAN_SENSORS; i++) {
176                 if (data->fan_present & BIT(i)) {
177                         err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i));
178                         if (err < 0)
179                                 goto exit;
180                         data->fan_input[i] = err;
181
182                         err = fts_read_byte(data->client,
183                                             FTS_REG_FAN_SOURCE(i));
184                         if (err < 0)
185                                 goto exit;
186                         data->fan_source[i] = err;
187                 } else {
188                         data->fan_input[i] = 0;
189                         data->fan_source[i] = FTS_FAN_SOURCE_INVALID;
190                 }
191         }
192
193         err = fts_read_byte(data->client, FTS_SENSOR_EVENT_REG);
194         if (err < 0)
195                 goto exit;
196         data->temp_alarm = err;
197
198         for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) {
199                 err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i));
200                 if (err < 0)
201                         goto exit;
202                 data->temp_input[i] = err;
203         }
204
205         for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) {
206                 err = fts_read_byte(data->client, FTS_REG_VOLT(i));
207                 if (err < 0)
208                         goto exit;
209                 data->volt[i] = err;
210         }
211         data->last_updated = jiffies;
212         err = 0;
213 exit:
214         mutex_unlock(&data->update_lock);
215         return err;
216 }
217
218 /*****************************************************************************/
219 /* Watchdog functions                                                        */
220 /*****************************************************************************/
221 static int fts_wd_set_resolution(struct fts_data *data,
222                                  enum WATCHDOG_RESOLUTION resolution)
223 {
224         int ret;
225
226         if (data->resolution == resolution)
227                 return 0;
228
229         ret = fts_read_byte(data->client, FTS_WATCHDOG_CONTROL);
230         if (ret < 0)
231                 return ret;
232
233         if ((resolution == seconds && ret & BIT(1)) ||
234             (resolution == minutes && (ret & BIT(1)) == 0)) {
235                 data->resolution = resolution;
236                 return 0;
237         }
238
239         if (resolution == seconds)
240                 ret |= BIT(1);
241         else
242                 ret &= ~BIT(1);
243
244         ret = fts_write_byte(data->client, FTS_WATCHDOG_CONTROL, ret);
245         if (ret < 0)
246                 return ret;
247
248         data->resolution = resolution;
249         return ret;
250 }
251
252 static int fts_wd_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
253 {
254         struct fts_data *data;
255         enum WATCHDOG_RESOLUTION resolution = seconds;
256         int ret;
257
258         data = watchdog_get_drvdata(wdd);
259         /* switch watchdog resolution to minutes if timeout does not fit
260          * into a byte
261          */
262         if (timeout > 0xFF) {
263                 timeout = DIV_ROUND_UP(timeout, 60) * 60;
264                 resolution = minutes;
265         }
266
267         ret = fts_wd_set_resolution(data, resolution);
268         if (ret < 0)
269                 return ret;
270
271         wdd->timeout = timeout;
272         return 0;
273 }
274
275 static int fts_wd_start(struct watchdog_device *wdd)
276 {
277         struct fts_data *data = watchdog_get_drvdata(wdd);
278
279         return fts_write_byte(data->client, FTS_WATCHDOG_TIME_PRESET,
280                               wdd->timeout / (u8)data->resolution);
281 }
282
283 static int fts_wd_stop(struct watchdog_device *wdd)
284 {
285         struct fts_data *data;
286
287         data = watchdog_get_drvdata(wdd);
288         return fts_write_byte(data->client, FTS_WATCHDOG_TIME_PRESET, 0);
289 }
290
291 static const struct watchdog_info fts_wd_info = {
292         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
293         .identity = "FTS Teutates Hardware Watchdog",
294 };
295
296 static const struct watchdog_ops fts_wd_ops = {
297         .owner = THIS_MODULE,
298         .start = fts_wd_start,
299         .stop = fts_wd_stop,
300         .set_timeout = fts_wd_set_timeout,
301 };
302
303 static int fts_watchdog_init(struct fts_data *data)
304 {
305         int timeout, ret;
306
307         watchdog_set_drvdata(&data->wdd, data);
308
309         timeout = fts_read_byte(data->client, FTS_WATCHDOG_TIME_PRESET);
310         if (timeout < 0)
311                 return timeout;
312
313         /* watchdog not running, set timeout to a default of 60 sec. */
314         if (timeout == 0) {
315                 ret = fts_wd_set_resolution(data, seconds);
316                 if (ret < 0)
317                         return ret;
318                 data->wdd.timeout = 60;
319         } else {
320                 ret = fts_read_byte(data->client, FTS_WATCHDOG_CONTROL);
321                 if (ret < 0)
322                         return ret;
323
324                 data->resolution = ret & BIT(1) ? seconds : minutes;
325                 data->wdd.timeout = timeout * (u8)data->resolution;
326                 set_bit(WDOG_HW_RUNNING, &data->wdd.status);
327         }
328
329         /* Register our watchdog part */
330         data->wdd.info = &fts_wd_info;
331         data->wdd.ops = &fts_wd_ops;
332         data->wdd.parent = &data->client->dev;
333         data->wdd.min_timeout = 1;
334
335         /* max timeout 255 minutes. */
336         data->wdd.max_hw_heartbeat_ms = 0xFF * 60 * MSEC_PER_SEC;
337
338         return devm_watchdog_register_device(&data->client->dev, &data->wdd);
339 }
340
341 static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, u32 attr,
342                               int channel)
343 {
344         switch (type) {
345         case hwmon_temp:
346                 switch (attr) {
347                 case hwmon_temp_input:
348                 case hwmon_temp_fault:
349                         return 0444;
350                 case hwmon_temp_alarm:
351                         return 0644;
352                 default:
353                         break;
354                 }
355                 break;
356         case hwmon_fan:
357                 switch (attr) {
358                 case hwmon_fan_input:
359                 case hwmon_fan_fault:
360                         return 0444;
361                 case hwmon_fan_alarm:
362                         return 0644;
363                 default:
364                         break;
365                 }
366                 break;
367         case hwmon_pwm:
368         case hwmon_in:
369                 return 0444;
370         default:
371                 break;
372         }
373
374         return 0;
375 }
376
377 static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
378                     long *val)
379 {
380         struct fts_data *data = dev_get_drvdata(dev);
381         int ret = fts_update_device(data);
382
383         if (ret < 0)
384                 return ret;
385
386         switch (type) {
387         case hwmon_temp:
388                 switch (attr) {
389                 case hwmon_temp_input:
390                         *val = (data->temp_input[channel] - 64) * 1000;
391
392                         return 0;
393                 case hwmon_temp_alarm:
394                         *val = !!(data->temp_alarm & BIT(channel));
395
396                         return 0;
397                 case hwmon_temp_fault:
398                         /* 00h Temperature = Sensor Error */;
399                         *val = (data->temp_input[channel] == 0);
400
401                         return 0;
402                 default:
403                         break;
404                 }
405                 break;
406         case hwmon_fan:
407                 switch (attr) {
408                 case hwmon_fan_input:
409                         *val = data->fan_input[channel] * 60;
410
411                         return 0;
412                 case hwmon_fan_alarm:
413                         *val = !!(data->fan_alarm & BIT(channel));
414
415                         return 0;
416                 case hwmon_fan_fault:
417                         *val = !(data->fan_present & BIT(channel));
418
419                         return 0;
420                 default:
421                         break;
422                 }
423                 break;
424         case hwmon_pwm:
425                 switch (attr) {
426                 case hwmon_pwm_auto_channels_temp:
427                         if (data->fan_source[channel] == FTS_FAN_SOURCE_INVALID)
428                                 *val = 0;
429                         else
430                                 *val = BIT(data->fan_source[channel]);
431
432                         return 0;
433                 default:
434                         break;
435                 }
436                 break;
437         case hwmon_in:
438                 switch (attr) {
439                 case hwmon_in_input:
440                         *val = DIV_ROUND_CLOSEST(data->volt[channel] * 3300, 255);
441
442                         return 0;
443                 default:
444                         break;
445                 }
446                 break;
447         default:
448                 break;
449         }
450
451         return -EOPNOTSUPP;
452 }
453
454 static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
455                      long val)
456 {
457         struct fts_data *data = dev_get_drvdata(dev);
458         int ret = fts_update_device(data);
459
460         if (ret < 0)
461                 return ret;
462
463         switch (type) {
464         case hwmon_temp:
465                 switch (attr) {
466                 case hwmon_temp_alarm:
467                         if (val)
468                                 return -EINVAL;
469
470                         mutex_lock(&data->update_lock);
471                         ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel));
472                         if (ret >= 0)
473                                 ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel),
474                                                      ret | 0x1);
475                         if (ret >= 0)
476                                 data->valid = false;
477
478                         mutex_unlock(&data->update_lock);
479                         if (ret < 0)
480                                 return ret;
481
482                         return 0;
483                 default:
484                         break;
485                 }
486                 break;
487         case hwmon_fan:
488                 switch (attr) {
489                 case hwmon_fan_alarm:
490                         if (val)
491                                 return -EINVAL;
492
493                         mutex_lock(&data->update_lock);
494                         ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel));
495                         if (ret >= 0)
496                                 ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel),
497                                                      ret | 0x1);
498                         if (ret >= 0)
499                                 data->valid = false;
500
501                         mutex_unlock(&data->update_lock);
502                         if (ret < 0)
503                                 return ret;
504
505                         return 0;
506                 default:
507                         break;
508                 }
509                 break;
510         default:
511                 break;
512         }
513
514         return -EOPNOTSUPP;
515 }
516
517 static const struct hwmon_ops fts_ops = {
518         .is_visible = fts_is_visible,
519         .read = fts_read,
520         .write = fts_write,
521 };
522
523 static const struct hwmon_channel_info * const fts_info[] = {
524         HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
525         HWMON_CHANNEL_INFO(temp,
526                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
527                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
528                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
529                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
530                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
531                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
532                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
533                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
534                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
535                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
536                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
537                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
538                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
539                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
540                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
541                            HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT
542                            ),
543         HWMON_CHANNEL_INFO(fan,
544                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
545                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
546                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
547                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
548                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
549                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
550                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
551                            HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT
552                            ),
553         HWMON_CHANNEL_INFO(pwm,
554                            HWMON_PWM_AUTO_CHANNELS_TEMP,
555                            HWMON_PWM_AUTO_CHANNELS_TEMP,
556                            HWMON_PWM_AUTO_CHANNELS_TEMP,
557                            HWMON_PWM_AUTO_CHANNELS_TEMP,
558                            HWMON_PWM_AUTO_CHANNELS_TEMP,
559                            HWMON_PWM_AUTO_CHANNELS_TEMP,
560                            HWMON_PWM_AUTO_CHANNELS_TEMP,
561                            HWMON_PWM_AUTO_CHANNELS_TEMP
562                            ),
563         HWMON_CHANNEL_INFO(in,
564                            HWMON_I_INPUT,
565                            HWMON_I_INPUT,
566                            HWMON_I_INPUT,
567                            HWMON_I_INPUT
568                            ),
569         NULL
570 };
571
572 static const struct hwmon_chip_info fts_chip_info = {
573         .ops = &fts_ops,
574         .info = fts_info,
575 };
576
577 /*****************************************************************************/
578 /* Module initialization / remove functions                                  */
579 /*****************************************************************************/
580 static int fts_detect(struct i2c_client *client,
581                       struct i2c_board_info *info)
582 {
583         int val;
584
585         /* detection works with revision greater or equal to 0x2b */
586         val = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG);
587         if (val < 0x2b)
588                 return -ENODEV;
589
590         /* Device Detect Regs must have 0x17 0x34 and 0x54 */
591         val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_1);
592         if (val != 0x17)
593                 return -ENODEV;
594
595         val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_2);
596         if (val != 0x34)
597                 return -ENODEV;
598
599         val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_3);
600         if (val != 0x54)
601                 return -ENODEV;
602
603         /*
604          * 0x10 == Baseboard Management Controller, 0x01 == Teutates
605          * Device ID Reg needs to be 0x11
606          */
607         val = i2c_smbus_read_byte_data(client, FTS_DEVICE_ID_REG);
608         if (val != 0x11)
609                 return -ENODEV;
610
611         strscpy(info->type, fts_id[0].name, I2C_NAME_SIZE);
612         info->flags = 0;
613         return 0;
614 }
615
616 static int fts_probe(struct i2c_client *client)
617 {
618         u8 revision;
619         struct fts_data *data;
620         int err;
621         s8 deviceid;
622         struct device *hwmon_dev;
623
624         if (client->addr != 0x73)
625                 return -ENODEV;
626
627         /* Baseboard Management Controller check */
628         deviceid = i2c_smbus_read_byte_data(client, FTS_DEVICE_ID_REG);
629         if (deviceid > 0 && (deviceid & 0xF0) == 0x10) {
630                 switch (deviceid & 0x0F) {
631                 case 0x01:
632                         break;
633                 default:
634                         dev_dbg(&client->dev,
635                                 "No Baseboard Management Controller\n");
636                         return -ENODEV;
637                 }
638         } else {
639                 dev_dbg(&client->dev, "No fujitsu board\n");
640                 return -ENODEV;
641         }
642
643         data = devm_kzalloc(&client->dev, sizeof(struct fts_data),
644                             GFP_KERNEL);
645         if (!data)
646                 return -ENOMEM;
647
648         mutex_init(&data->update_lock);
649         mutex_init(&data->access_lock);
650         data->client = client;
651         dev_set_drvdata(&client->dev, data);
652
653         err = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG);
654         if (err < 0)
655                 return err;
656         revision = err;
657
658         hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "ftsteutates", data,
659                                                          &fts_chip_info, NULL);
660         if (IS_ERR(hwmon_dev))
661                 return PTR_ERR(hwmon_dev);
662
663         err = fts_watchdog_init(data);
664         if (err)
665                 return err;
666
667         dev_info(&client->dev, "Detected FTS Teutates chip, revision: %d.%d\n",
668                  (revision & 0xF0) >> 4, revision & 0x0F);
669         return 0;
670 }
671
672 /*****************************************************************************/
673 /* Module Details                                                            */
674 /*****************************************************************************/
675 static struct i2c_driver fts_driver = {
676         .class = I2C_CLASS_HWMON,
677         .driver = {
678                 .name = "ftsteutates",
679         },
680         .id_table = fts_id,
681         .probe = fts_probe,
682         .detect = fts_detect,
683         .address_list = normal_i2c,
684 };
685
686 module_i2c_driver(fts_driver);
687
688 MODULE_AUTHOR("Thilo Cestonaro <thilo.cestonaro@ts.fujitsu.com>");
689 MODULE_DESCRIPTION("FTS Teutates driver");
690 MODULE_LICENSE("GPL");