Merge tag 'drm-next-2018-12-14' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / fsi / fsi-scom.c
1 /*
2  * SCOM FSI Client device driver
3  *
4  * Copyright (C) IBM Corporation 2016
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <linux/fsi.h>
17 #include <linux/module.h>
18 #include <linux/cdev.h>
19 #include <linux/delay.h>
20 #include <linux/fs.h>
21 #include <linux/uaccess.h>
22 #include <linux/slab.h>
23 #include <linux/list.h>
24
25 #include <uapi/linux/fsi.h>
26
27 #define FSI_ENGID_SCOM          0x5
28
29 /* SCOM engine register set */
30 #define SCOM_DATA0_REG          0x00
31 #define SCOM_DATA1_REG          0x04
32 #define SCOM_CMD_REG            0x08
33 #define SCOM_FSI2PIB_RESET_REG  0x18
34 #define SCOM_STATUS_REG         0x1C /* Read */
35 #define SCOM_PIB_RESET_REG      0x1C /* Write */
36
37 /* Command register */
38 #define SCOM_WRITE_CMD          0x80000000
39 #define SCOM_READ_CMD           0x00000000
40
41 /* Status register bits */
42 #define SCOM_STATUS_ERR_SUMMARY         0x80000000
43 #define SCOM_STATUS_PROTECTION          0x01000000
44 #define SCOM_STATUS_PARITY              0x04000000
45 #define SCOM_STATUS_PIB_ABORT           0x00100000
46 #define SCOM_STATUS_PIB_RESP_MASK       0x00007000
47 #define SCOM_STATUS_PIB_RESP_SHIFT      12
48
49 #define SCOM_STATUS_ANY_ERR             (SCOM_STATUS_ERR_SUMMARY | \
50                                          SCOM_STATUS_PROTECTION | \
51                                          SCOM_STATUS_PARITY |     \
52                                          SCOM_STATUS_PIB_ABORT | \
53                                          SCOM_STATUS_PIB_RESP_MASK)
54 /* SCOM address encodings */
55 #define XSCOM_ADDR_IND_FLAG             BIT_ULL(63)
56 #define XSCOM_ADDR_INF_FORM1            BIT_ULL(60)
57
58 /* SCOM indirect stuff */
59 #define XSCOM_ADDR_DIRECT_PART          0x7fffffffull
60 #define XSCOM_ADDR_INDIRECT_PART        0x000fffff00000000ull
61 #define XSCOM_DATA_IND_READ             BIT_ULL(63)
62 #define XSCOM_DATA_IND_COMPLETE         BIT_ULL(31)
63 #define XSCOM_DATA_IND_ERR_MASK         0x70000000ull
64 #define XSCOM_DATA_IND_ERR_SHIFT        28
65 #define XSCOM_DATA_IND_DATA             0x0000ffffull
66 #define XSCOM_DATA_IND_FORM1_DATA       0x000fffffffffffffull
67 #define XSCOM_ADDR_FORM1_LOW            0x000ffffffffull
68 #define XSCOM_ADDR_FORM1_HI             0xfff00000000ull
69 #define XSCOM_ADDR_FORM1_HI_SHIFT       20
70
71 /* Retries */
72 #define SCOM_MAX_RETRIES                100     /* Retries on busy */
73 #define SCOM_MAX_IND_RETRIES            10      /* Retries indirect not ready */
74
75 struct scom_device {
76         struct list_head link;
77         struct fsi_device *fsi_dev;
78         struct device dev;
79         struct cdev cdev;
80         struct mutex lock;
81         bool dead;
82 };
83
84 static int __put_scom(struct scom_device *scom_dev, uint64_t value,
85                       uint32_t addr, uint32_t *status)
86 {
87         __be32 data, raw_status;
88         int rc;
89
90         data = cpu_to_be32((value >> 32) & 0xffffffff);
91         rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
92                                 sizeof(uint32_t));
93         if (rc)
94                 return rc;
95
96         data = cpu_to_be32(value & 0xffffffff);
97         rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
98                                 sizeof(uint32_t));
99         if (rc)
100                 return rc;
101
102         data = cpu_to_be32(SCOM_WRITE_CMD | addr);
103         rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
104                                 sizeof(uint32_t));
105         if (rc)
106                 return rc;
107         rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
108                              sizeof(uint32_t));
109         if (rc)
110                 return rc;
111         *status = be32_to_cpu(raw_status);
112
113         return 0;
114 }
115
116 static int __get_scom(struct scom_device *scom_dev, uint64_t *value,
117                       uint32_t addr, uint32_t *status)
118 {
119         __be32 data, raw_status;
120         int rc;
121
122
123         *value = 0ULL;
124         data = cpu_to_be32(SCOM_READ_CMD | addr);
125         rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
126                                 sizeof(uint32_t));
127         if (rc)
128                 return rc;
129         rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
130                              sizeof(uint32_t));
131         if (rc)
132                 return rc;
133
134         /*
135          * Read the data registers even on error, so we don't have
136          * to interpret the status register here.
137          */
138         rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
139                                 sizeof(uint32_t));
140         if (rc)
141                 return rc;
142         *value |= (uint64_t)be32_to_cpu(data) << 32;
143         rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
144                                 sizeof(uint32_t));
145         if (rc)
146                 return rc;
147         *value |= be32_to_cpu(data);
148         *status = be32_to_cpu(raw_status);
149
150         return rc;
151 }
152
153 static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
154                                    uint64_t addr, uint32_t *status)
155 {
156         uint64_t ind_data, ind_addr;
157         int rc, retries, err = 0;
158
159         if (value & ~XSCOM_DATA_IND_DATA)
160                 return -EINVAL;
161
162         ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
163         ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | value;
164         rc = __put_scom(scom, ind_data, ind_addr, status);
165         if (rc || (*status & SCOM_STATUS_ANY_ERR))
166                 return rc;
167
168         for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
169                 rc = __get_scom(scom, &ind_data, addr, status);
170                 if (rc || (*status & SCOM_STATUS_ANY_ERR))
171                         return rc;
172
173                 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
174                 *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
175                 if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
176                         return 0;
177
178                 msleep(1);
179         }
180         return rc;
181 }
182
183 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
184                                    uint64_t addr, uint32_t *status)
185 {
186         uint64_t ind_data, ind_addr;
187
188         if (value & ~XSCOM_DATA_IND_FORM1_DATA)
189                 return -EINVAL;
190
191         ind_addr = addr & XSCOM_ADDR_FORM1_LOW;
192         ind_data = value | (addr & XSCOM_ADDR_FORM1_HI) << XSCOM_ADDR_FORM1_HI_SHIFT;
193         return __put_scom(scom, ind_data, ind_addr, status);
194 }
195
196 static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
197                                    uint64_t addr, uint32_t *status)
198 {
199         uint64_t ind_data, ind_addr;
200         int rc, retries, err = 0;
201
202         ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
203         ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
204         rc = __put_scom(scom, ind_data, ind_addr, status);
205         if (rc || (*status & SCOM_STATUS_ANY_ERR))
206                 return rc;
207
208         for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
209                 rc = __get_scom(scom, &ind_data, addr, status);
210                 if (rc || (*status & SCOM_STATUS_ANY_ERR))
211                         return rc;
212
213                 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
214                 *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
215                 *value = ind_data & XSCOM_DATA_IND_DATA;
216
217                 if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
218                         return 0;
219
220                 msleep(1);
221         }
222         return rc;
223 }
224
225 static int raw_put_scom(struct scom_device *scom, uint64_t value,
226                         uint64_t addr, uint32_t *status)
227 {
228         if (addr & XSCOM_ADDR_IND_FLAG) {
229                 if (addr & XSCOM_ADDR_INF_FORM1)
230                         return put_indirect_scom_form1(scom, value, addr, status);
231                 else
232                         return put_indirect_scom_form0(scom, value, addr, status);
233         } else
234                 return __put_scom(scom, value, addr, status);
235 }
236
237 static int raw_get_scom(struct scom_device *scom, uint64_t *value,
238                         uint64_t addr, uint32_t *status)
239 {
240         if (addr & XSCOM_ADDR_IND_FLAG) {
241                 if (addr & XSCOM_ADDR_INF_FORM1)
242                         return -ENXIO;
243                 return get_indirect_scom_form0(scom, value, addr, status);
244         } else
245                 return __get_scom(scom, value, addr, status);
246 }
247
248 static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
249 {
250         uint32_t dummy = -1;
251
252         if (status & SCOM_STATUS_PROTECTION)
253                 return -EPERM;
254         if (status & SCOM_STATUS_PARITY) {
255                 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
256                                  sizeof(uint32_t));
257                 return -EIO;
258         }
259         /* Return -EBUSY on PIB abort to force a retry */
260         if (status & SCOM_STATUS_PIB_ABORT)
261                 return -EBUSY;
262         if (status & SCOM_STATUS_ERR_SUMMARY) {
263                 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
264                                  sizeof(uint32_t));
265                 return -EIO;
266         }
267         return 0;
268 }
269
270 static int handle_pib_status(struct scom_device *scom, uint8_t status)
271 {
272         uint32_t dummy = -1;
273
274         if (status == SCOM_PIB_SUCCESS)
275                 return 0;
276         if (status == SCOM_PIB_BLOCKED)
277                 return -EBUSY;
278
279         /* Reset the bridge */
280         fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
281                          sizeof(uint32_t));
282
283         switch(status) {
284         case SCOM_PIB_OFFLINE:
285                 return -ENODEV;
286         case SCOM_PIB_BAD_ADDR:
287                 return -ENXIO;
288         case SCOM_PIB_TIMEOUT:
289                 return -ETIMEDOUT;
290         case SCOM_PIB_PARTIAL:
291         case SCOM_PIB_CLK_ERR:
292         case SCOM_PIB_PARITY_ERR:
293         default:
294                 return -EIO;
295         }
296 }
297
298 static int put_scom(struct scom_device *scom, uint64_t value,
299                     uint64_t addr)
300 {
301         uint32_t status, dummy = -1;
302         int rc, retries;
303
304         for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
305                 rc = raw_put_scom(scom, value, addr, &status);
306                 if (rc) {
307                         /* Try resetting the bridge if FSI fails */
308                         if (rc != -ENODEV && retries == 0) {
309                                 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
310                                                  &dummy, sizeof(uint32_t));
311                                 rc = -EBUSY;
312                         } else
313                                 return rc;
314                 } else
315                         rc = handle_fsi2pib_status(scom, status);
316                 if (rc && rc != -EBUSY)
317                         break;
318                 if (rc == 0) {
319                         rc = handle_pib_status(scom,
320                                                (status & SCOM_STATUS_PIB_RESP_MASK)
321                                                >> SCOM_STATUS_PIB_RESP_SHIFT);
322                         if (rc && rc != -EBUSY)
323                                 break;
324                 }
325                 if (rc == 0)
326                         break;
327                 msleep(1);
328         }
329         return rc;
330 }
331
332 static int get_scom(struct scom_device *scom, uint64_t *value,
333                     uint64_t addr)
334 {
335         uint32_t status, dummy = -1;
336         int rc, retries;
337
338         for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
339                 rc = raw_get_scom(scom, value, addr, &status);
340                 if (rc) {
341                         /* Try resetting the bridge if FSI fails */
342                         if (rc != -ENODEV && retries == 0) {
343                                 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
344                                                  &dummy, sizeof(uint32_t));
345                                 rc = -EBUSY;
346                         } else
347                                 return rc;
348                 } else
349                         rc = handle_fsi2pib_status(scom, status);
350                 if (rc && rc != -EBUSY)
351                         break;
352                 if (rc == 0) {
353                         rc = handle_pib_status(scom,
354                                                (status & SCOM_STATUS_PIB_RESP_MASK)
355                                                >> SCOM_STATUS_PIB_RESP_SHIFT);
356                         if (rc && rc != -EBUSY)
357                                 break;
358                 }
359                 if (rc == 0)
360                         break;
361                 msleep(1);
362         }
363         return rc;
364 }
365
366 static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
367                          loff_t *offset)
368 {
369         struct scom_device *scom = filep->private_data;
370         struct device *dev = &scom->fsi_dev->dev;
371         uint64_t val;
372         int rc;
373
374         if (len != sizeof(uint64_t))
375                 return -EINVAL;
376
377         mutex_lock(&scom->lock);
378         if (scom->dead)
379                 rc = -ENODEV;
380         else
381                 rc = get_scom(scom, &val, *offset);
382         mutex_unlock(&scom->lock);
383         if (rc) {
384                 dev_dbg(dev, "get_scom fail:%d\n", rc);
385                 return rc;
386         }
387
388         rc = copy_to_user(buf, &val, len);
389         if (rc)
390                 dev_dbg(dev, "copy to user failed:%d\n", rc);
391
392         return rc ? rc : len;
393 }
394
395 static ssize_t scom_write(struct file *filep, const char __user *buf,
396                           size_t len, loff_t *offset)
397 {
398         int rc;
399         struct scom_device *scom = filep->private_data;
400         struct device *dev = &scom->fsi_dev->dev;
401         uint64_t val;
402
403         if (len != sizeof(uint64_t))
404                 return -EINVAL;
405
406         rc = copy_from_user(&val, buf, len);
407         if (rc) {
408                 dev_dbg(dev, "copy from user failed:%d\n", rc);
409                 return -EINVAL;
410         }
411
412         mutex_lock(&scom->lock);
413         if (scom->dead)
414                 rc = -ENODEV;
415         else
416                 rc = put_scom(scom, val, *offset);
417         mutex_unlock(&scom->lock);
418         if (rc) {
419                 dev_dbg(dev, "put_scom failed with:%d\n", rc);
420                 return rc;
421         }
422
423         return len;
424 }
425
426 static loff_t scom_llseek(struct file *file, loff_t offset, int whence)
427 {
428         switch (whence) {
429         case SEEK_CUR:
430                 break;
431         case SEEK_SET:
432                 file->f_pos = offset;
433                 break;
434         default:
435                 return -EINVAL;
436         }
437
438         return offset;
439 }
440
441 static void raw_convert_status(struct scom_access *acc, uint32_t status)
442 {
443         acc->pib_status = (status & SCOM_STATUS_PIB_RESP_MASK) >>
444                 SCOM_STATUS_PIB_RESP_SHIFT;
445         acc->intf_errors = 0;
446
447         if (status & SCOM_STATUS_PROTECTION)
448                 acc->intf_errors |= SCOM_INTF_ERR_PROTECTION;
449         else if (status & SCOM_STATUS_PARITY)
450                 acc->intf_errors |= SCOM_INTF_ERR_PARITY;
451         else if (status & SCOM_STATUS_PIB_ABORT)
452                 acc->intf_errors |= SCOM_INTF_ERR_ABORT;
453         else if (status & SCOM_STATUS_ERR_SUMMARY)
454                 acc->intf_errors |= SCOM_INTF_ERR_UNKNOWN;
455 }
456
457 static int scom_raw_read(struct scom_device *scom, void __user *argp)
458 {
459         struct scom_access acc;
460         uint32_t status;
461         int rc;
462
463         if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
464                 return -EFAULT;
465
466         rc = raw_get_scom(scom, &acc.data, acc.addr, &status);
467         if (rc)
468                 return rc;
469         raw_convert_status(&acc, status);
470         if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
471                 return -EFAULT;
472         return 0;
473 }
474
475 static int scom_raw_write(struct scom_device *scom, void __user *argp)
476 {
477         u64 prev_data, mask, data;
478         struct scom_access acc;
479         uint32_t status;
480         int rc;
481
482         if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
483                 return -EFAULT;
484
485         if (acc.mask) {
486                 rc = raw_get_scom(scom, &prev_data, acc.addr, &status);
487                 if (rc)
488                         return rc;
489                 if (status & SCOM_STATUS_ANY_ERR)
490                         goto fail;
491                 mask = acc.mask;
492         } else {
493                 prev_data = mask = -1ull;
494         }
495         data = (prev_data & ~mask) | (acc.data & mask);
496         rc = raw_put_scom(scom, data, acc.addr, &status);
497         if (rc)
498                 return rc;
499  fail:
500         raw_convert_status(&acc, status);
501         if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
502                 return -EFAULT;
503         return 0;
504 }
505
506 static int scom_reset(struct scom_device *scom, void __user *argp)
507 {
508         uint32_t flags, dummy = -1;
509         int rc = 0;
510
511         if (get_user(flags, (__u32 __user *)argp))
512                 return -EFAULT;
513         if (flags & SCOM_RESET_PIB)
514                 rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy,
515                                       sizeof(uint32_t));
516         if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF)))
517                 rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
518                                       sizeof(uint32_t));
519         return rc;
520 }
521
522 static int scom_check(struct scom_device *scom, void __user *argp)
523 {
524         /* Still need to find out how to get "protected" */
525         return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp);
526 }
527
528 static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
529 {
530         struct scom_device *scom = file->private_data;
531         void __user *argp = (void __user *)arg;
532         int rc = -ENOTTY;
533
534         mutex_lock(&scom->lock);
535         if (scom->dead) {
536                 mutex_unlock(&scom->lock);
537                 return -ENODEV;
538         }
539         switch(cmd) {
540         case FSI_SCOM_CHECK:
541                 rc = scom_check(scom, argp);
542                 break;
543         case FSI_SCOM_READ:
544                 rc = scom_raw_read(scom, argp);
545                 break;
546         case FSI_SCOM_WRITE:
547                 rc = scom_raw_write(scom, argp);
548                 break;
549         case FSI_SCOM_RESET:
550                 rc = scom_reset(scom, argp);
551                 break;
552         }
553         mutex_unlock(&scom->lock);
554         return rc;
555 }
556
557 static int scom_open(struct inode *inode, struct file *file)
558 {
559         struct scom_device *scom = container_of(inode->i_cdev, struct scom_device, cdev);
560
561         file->private_data = scom;
562
563         return 0;
564 }
565
566 static const struct file_operations scom_fops = {
567         .owner          = THIS_MODULE,
568         .open           = scom_open,
569         .llseek         = scom_llseek,
570         .read           = scom_read,
571         .write          = scom_write,
572         .unlocked_ioctl = scom_ioctl,
573 };
574
575 static void scom_free(struct device *dev)
576 {
577         struct scom_device *scom = container_of(dev, struct scom_device, dev);
578
579         put_device(&scom->fsi_dev->dev);
580         kfree(scom);
581 }
582
583 static int scom_probe(struct device *dev)
584 {
585         struct fsi_device *fsi_dev = to_fsi_dev(dev);
586         struct scom_device *scom;
587         int rc, didx;
588
589         scom = kzalloc(sizeof(*scom), GFP_KERNEL);
590         if (!scom)
591                 return -ENOMEM;
592         dev_set_drvdata(dev, scom);
593         mutex_init(&scom->lock);
594
595         /* Grab a reference to the device (parent of our cdev), we'll drop it later */
596         if (!get_device(dev)) {
597                 kfree(scom);
598                 return -ENODEV;
599         }
600         scom->fsi_dev = fsi_dev;
601
602         /* Create chardev for userspace access */
603         scom->dev.type = &fsi_cdev_type;
604         scom->dev.parent = dev;
605         scom->dev.release = scom_free;
606         device_initialize(&scom->dev);
607
608         /* Allocate a minor in the FSI space */
609         rc = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx);
610         if (rc)
611                 goto err;
612
613         dev_set_name(&scom->dev, "scom%d", didx);
614         cdev_init(&scom->cdev, &scom_fops);
615         rc = cdev_device_add(&scom->cdev, &scom->dev);
616         if (rc) {
617                 dev_err(dev, "Error %d creating char device %s\n",
618                         rc, dev_name(&scom->dev));
619                 goto err_free_minor;
620         }
621
622         return 0;
623  err_free_minor:
624         fsi_free_minor(scom->dev.devt);
625  err:
626         put_device(&scom->dev);
627         return rc;
628 }
629
630 static int scom_remove(struct device *dev)
631 {
632         struct scom_device *scom = dev_get_drvdata(dev);
633
634         mutex_lock(&scom->lock);
635         scom->dead = true;
636         mutex_unlock(&scom->lock);
637         cdev_device_del(&scom->cdev, &scom->dev);
638         fsi_free_minor(scom->dev.devt);
639         put_device(&scom->dev);
640
641         return 0;
642 }
643
644 static struct fsi_device_id scom_ids[] = {
645         {
646                 .engine_type = FSI_ENGID_SCOM,
647                 .version = FSI_VERSION_ANY,
648         },
649         { 0 }
650 };
651
652 static struct fsi_driver scom_drv = {
653         .id_table = scom_ids,
654         .drv = {
655                 .name = "scom",
656                 .bus = &fsi_bus_type,
657                 .probe = scom_probe,
658                 .remove = scom_remove,
659         }
660 };
661
662 static int scom_init(void)
663 {
664         return fsi_driver_register(&scom_drv);
665 }
666
667 static void scom_exit(void)
668 {
669         fsi_driver_unregister(&scom_drv);
670 }
671
672 module_init(scom_init);
673 module_exit(scom_exit);
674 MODULE_LICENSE("GPL");