xref: /linux/drivers/fsi/fsi-scom.c (revision b7019ac550eb3916f34d79db583e9b7ea2524afa)
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");
675