]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/misc/xilinx_sdfec.c
misc: xilinx-sdfec: Fix enum xsdfec_order values
[zynq/linux.git] / drivers / misc / xilinx_sdfec.c
1 /*
2  * Xilinx SDFEC
3  *
4  * Copyright (C) 2016 - 2017 Xilinx, Inc.
5  *
6  * Description:
7  * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)
8  * IP. It exposes a char device interface in sysfs and supports file
9  * operations like  open(), close() and ioctl().
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <linux/cdev.h>
26 #include <linux/device.h>
27 #include <linux/fs.h>
28 #include <linux/io.h>
29 #include <linux/interrupt.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/of.h>
33 #include <linux/of_platform.h>
34 #include <linux/platform_device.h>
35 #include <linux/poll.h>
36 #include <linux/slab.h>
37 #include <linux/uaccess.h>
38
39 #include <uapi/misc/xilinx_sdfec.h>
40
41 #define DRIVER_NAME     "xilinx_sdfec"
42 #define DRIVER_VERSION  "0.2"
43 #define DRIVER_MAX_DEV  (6)
44
45 static  struct class *xsdfec_class;
46 static atomic_t xsdfec_ndevs = ATOMIC_INIT(0);
47 static dev_t xsdfec_devt;
48
49 /* Xilinx SDFEC Register Map */
50 #define XSDFEC_AXI_WR_PROTECT_ADDR              (0x00000)
51 #define XSDFEC_CODE_WR_PROTECT_ADDR             (0x00004)
52 #define XSDFEC_ACTIVE_ADDR                      (0x00008)
53 #define XSDFEC_AXIS_WIDTH_ADDR                  (0x0000c)
54 #define XSDFEC_AXIS_ENABLE_ADDR                 (0x00010)
55 #define XSDFEC_AXIS_ENABLE_MASK                 (0x0001F)
56 #define XSDFEC_FEC_CODE_ADDR                    (0x00014)
57 #define XSDFEC_ORDER_ADDR                       (0x00018)
58
59 /* Interrupt Status Register Bit Mask*/
60 #define XSDFEC_ISR_MASK                         (0x0003F)
61 /* Interrupt Status Register */
62 #define XSDFEC_ISR_ADDR                         (0x0001c)
63 /* Write Only - Interrupt Enable Register */
64 #define XSDFEC_IER_ADDR                         (0x00020)
65 /* Write Only - Interrupt Disable Register */
66 #define XSDFEC_IDR_ADDR                         (0x00024)
67 /* Read Only - Interrupt Mask Register */
68 #define XSDFEC_IMR_ADDR                         (0x00028)
69
70 /* Single Bit Errors */
71 #define XSDFEC_ECC_ISR_SBE                      (0x7FF)
72 /* Multi Bit Errors */
73 #define XSDFEC_ECC_ISR_MBE                      (0x3FF800)
74 /* ECC Interrupt Status Bit Mask */
75 #define XSDFEC_ECC_ISR_MASK     (XSDFEC_ECC_ISR_SBE | XSDFEC_ECC_ISR_MBE)
76
77 /* Multi Bit Error Postion */
78 #define XSDFEC_ECC_MULTI_BIT_POS                (11)
79 #define XSDFEC_ERROR_MAX_THRESHOLD              (100)
80
81 /* ECC Interrupt Status Register */
82 #define XSDFEC_ECC_ISR_ADDR                     (0x0002c)
83 /* Write Only - ECC Interrupt Enable Register */
84 #define XSDFEC_ECC_IER_ADDR                     (0x00030)
85 /* Write Only - ECC Interrupt Disable Register */
86 #define XSDFEC_ECC_IDR_ADDR                     (0x00034)
87 /* Read Only - ECC Interrupt Mask Register */
88 #define XSDFEC_ECC_IMR_ADDR                     (0x00038)
89
90 #define XSDFEC_BYPASS_ADDR                      (0x0003c)
91 #define XSDFEC_TEST_EMA_ADDR_BASE               (0x00080)
92 #define XSDFEC_TEST_EMA_ADDR_HIGH               (0x00089)
93 #define XSDFEC_TURBO_ADDR                       (0x00100)
94 #define XSDFEC_LDPC_CODE_REG0_ADDR_BASE         (0x02000)
95 #define XSDFEC_LDPC_CODE_REG0_ADDR_HIGH         (0x021fc)
96 #define XSDFEC_LDPC_CODE_REG1_ADDR_BASE         (0x02004)
97 #define XSDFEC_LDPC_CODE_REG1_ADDR_HIGH         (0x02200)
98 #define XSDFEC_LDPC_CODE_REG2_ADDR_BASE         (0x02008)
99 #define XSDFEC_LDPC_CODE_REG2_ADDR_HIGH         (0x02204)
100 #define XSDFEC_LDPC_CODE_REG3_ADDR_BASE         (0x0200c)
101 #define XSDFEC_LDPC_CODE_REG3_ADDR_HIGH         (0x02208)
102
103 /**
104  * struct xsdfec_dev - Driver data for SDFEC
105  * @regs: device physical base address
106  * @dev: pointer to device struct
107  * @fec_id: Instance number
108  * @intr_enabled: indicates IRQ enabled
109  * @wr_protect: indicates Write Protect enabled
110  * @code: LDPC or Turbo Codes being used
111  * @order: In-Order or Out-of-Order
112  * @state: State of the SDFEC device
113  * @op_mode: Operating in Encode or Decode
114  * @isr_err_count: Count of ISR errors
115  * @cecc_count: Count of Correctable ECC errors (SBE)
116  * @uecc_count: Count of Uncorrectable ECC errors (MBE)
117  * @reset_count: Count of Resets requested
118  * @open_count: Count of char device being opened
119  * @irq: IRQ number
120  * @xsdfec_cdev: Character device handle
121  * @sc_off: Shared Scale Table Offset
122  * @qc_off: Shared Circulant Table Offset
123  * @la_off: Shared Layer Table Offset
124  * @waitq: Driver wait queue
125  *
126  * This structure contains necessary state for SDFEC driver to operate
127  */
128 struct xsdfec_dev {
129         void __iomem *regs;
130         struct device *dev;
131         s32  fec_id;
132         bool intr_enabled;
133         bool wr_protect;
134         enum xsdfec_code code;
135         enum xsdfec_order order;
136         enum xsdfec_state state;
137         enum xsdfec_op_mode op_mode;
138         atomic_t isr_err_count;
139         atomic_t cecc_count;
140         atomic_t uecc_count;
141         atomic_t reset_count;
142         atomic_t open_count;
143         int  irq;
144         struct cdev xsdfec_cdev;
145         int sc_off;
146         int qc_off;
147         int la_off;
148         wait_queue_head_t waitq;
149 };
150
151 static inline void
152 xsdfec_regwrite(struct xsdfec_dev *xsdfec, u32 addr, u32 value)
153 {
154         if (xsdfec->wr_protect) {
155                 dev_err(xsdfec->dev, "SDFEC in write protect");
156                 return;
157         }
158
159         dev_dbg(xsdfec->dev,
160                 "Writing 0x%x to offset 0x%x", value, addr);
161         iowrite32(value, xsdfec->regs + addr);
162 }
163
164 static inline u32
165 xsdfec_regread(struct xsdfec_dev *xsdfec, u32 addr)
166 {
167         u32 rval;
168
169         rval = ioread32(xsdfec->regs + addr);
170         dev_info(xsdfec->dev,
171                  "Read value = 0x%x from offset 0x%x",
172                  rval, addr);
173         return rval;
174 }
175
176 #define XSDFEC_WRITE_PROTECT_ENABLE     (1)
177 #define XSDFEC_WRITE_PROTECT_DISABLE    (0)
178 static void
179 xsdfec_wr_protect(struct xsdfec_dev *xsdfec, bool wr_pr)
180 {
181         if (wr_pr) {
182                 xsdfec_regwrite(xsdfec,
183                                 XSDFEC_CODE_WR_PROTECT_ADDR,
184                                 XSDFEC_WRITE_PROTECT_ENABLE);
185                 xsdfec_regwrite(xsdfec,
186                                 XSDFEC_AXI_WR_PROTECT_ADDR,
187                                 XSDFEC_WRITE_PROTECT_ENABLE);
188         } else {
189                 xsdfec_regwrite(xsdfec,
190                                 XSDFEC_AXI_WR_PROTECT_ADDR,
191                                 XSDFEC_WRITE_PROTECT_DISABLE);
192                 xsdfec_regwrite(xsdfec,
193                                 XSDFEC_CODE_WR_PROTECT_ADDR,
194                                 XSDFEC_WRITE_PROTECT_DISABLE);
195         }
196         xsdfec->wr_protect = wr_pr;
197 }
198
199 static int
200 xsdfec_dev_open(struct inode *iptr, struct file *fptr)
201 {
202         struct xsdfec_dev *xsdfec;
203
204         xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
205         if (!xsdfec)
206                 return  -EAGAIN;
207
208         /* Only one open per device at a time */
209         if (!atomic_dec_and_test(&xsdfec->open_count))
210                 return -EBUSY;
211
212         fptr->private_data = xsdfec;
213         return 0;
214 }
215
216 static int
217 xsdfec_dev_release(struct inode *iptr, struct file *fptr)
218 {
219         struct xsdfec_dev *xsdfec;
220
221         xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
222         if (!xsdfec)
223                 return -EAGAIN;
224
225         atomic_inc(&xsdfec->open_count);
226         return 0;
227 }
228
229 #define XSDFEC_IS_ACTIVITY_SET  (0x1)
230 static int
231 xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
232 {
233         struct xsdfec_status status;
234         int err = 0;
235
236         status.fec_id = xsdfec->fec_id;
237         status.state = xsdfec->state;
238         status.code = xsdfec->code;
239         status.order = xsdfec->order;
240         status.mode = xsdfec->op_mode;
241         status.activity  =
242                 (xsdfec_regread(xsdfec,
243                                 XSDFEC_ACTIVE_ADDR) &
244                                 XSDFEC_IS_ACTIVITY_SET);
245         status.cecc_count = atomic_read(&xsdfec->cecc_count);
246
247         err = copy_to_user(arg, &status, sizeof(status));
248         if (err) {
249                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
250                         __func__, xsdfec->fec_id);
251                 err = -EFAULT;
252         }
253         return err;
254 }
255
256 static int
257 xsdfec_get_config(struct xsdfec_dev *xsdfec, void __user *arg)
258 {
259         struct xsdfec_config config;
260         int err = 0;
261
262         config.fec_id = xsdfec->fec_id;
263         config.state = xsdfec->state;
264         config.code = xsdfec->code;
265         config.mode = xsdfec->op_mode;
266         config.order = xsdfec->order;
267
268         err = copy_to_user(arg, &config, sizeof(config));
269         if (err) {
270                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
271                         __func__, xsdfec->fec_id);
272                 err = -EFAULT;
273         }
274         return err;
275 }
276
277 static int
278 xsdfec_isr_enable(struct xsdfec_dev *xsdfec, bool enable)
279 {
280         u32 mask_read;
281
282         if (enable) {
283                 /* Enable */
284                 xsdfec_regwrite(xsdfec, XSDFEC_IER_ADDR,
285                                 XSDFEC_ISR_MASK);
286                 mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);
287                 if (mask_read & XSDFEC_ISR_MASK) {
288                         dev_err(xsdfec->dev,
289                                 "SDFEC enabling irq with IER failed");
290                         return -EIO;
291                 }
292         } else {
293                 /* Disable */
294                 xsdfec_regwrite(xsdfec, XSDFEC_IDR_ADDR,
295                                 XSDFEC_ISR_MASK);
296                 mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);
297                 if ((mask_read & XSDFEC_ISR_MASK) != XSDFEC_ISR_MASK) {
298                         dev_err(xsdfec->dev,
299                                 "SDFEC disabling irq with IDR failed");
300                         return -EIO;
301                 }
302         }
303         return 0;
304 }
305
306 static int
307 xsdfec_ecc_isr_enable(struct xsdfec_dev *xsdfec, bool enable)
308 {
309         u32 mask_read;
310
311         if (enable) {
312                 /* Enable */
313                 xsdfec_regwrite(xsdfec, XSDFEC_ECC_IER_ADDR,
314                                 XSDFEC_ECC_ISR_MASK);
315                 mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);
316                 if (mask_read & XSDFEC_ECC_ISR_MASK) {
317                         dev_err(xsdfec->dev,
318                                 "SDFEC enabling ECC irq with ECC IER failed");
319                         return -EIO;
320                 }
321         } else {
322                 /* Disable */
323                 xsdfec_regwrite(xsdfec, XSDFEC_ECC_IDR_ADDR,
324                                 XSDFEC_ECC_ISR_MASK);
325                 mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);
326                 if ((mask_read & XSDFEC_ECC_ISR_MASK) != XSDFEC_ECC_ISR_MASK) {
327                         dev_err(xsdfec->dev,
328                                 "SDFEC disable ECC irq with ECC IDR failed");
329                         return -EIO;
330                 }
331         }
332         return 0;
333 }
334
335 static int
336 xsdfec_set_irq(struct xsdfec_dev *xsdfec, void __user *arg)
337 {
338         struct xsdfec_irq  irq;
339         int err = 0;
340
341         err = copy_from_user(&irq, arg, sizeof(irq));
342         if (err) {
343                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
344                         __func__, xsdfec->fec_id);
345                 return -EFAULT;
346         }
347
348         /* Setup tlast related IRQ */
349         if (irq.enable_isr) {
350                 err = xsdfec_isr_enable(xsdfec, true);
351                 if (err < 0)
352                         return err;
353         }
354
355         /* Setup ECC related IRQ */
356         if (irq.enable_ecc_isr) {
357                 err = xsdfec_ecc_isr_enable(xsdfec, true);
358                 if (err < 0)
359                         return err;
360         }
361
362         return 0;
363 }
364
365 #define XSDFEC_TURBO_SCALE_MASK         (0xF)
366 #define XSDFEC_TURBO_SCALE_BIT_POS      (8)
367 static int
368 xsdfec_set_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
369 {
370         struct xsdfec_turbo turbo;
371         int err = 0;
372         u32 turbo_write = 0;
373
374         err = copy_from_user(&turbo, arg, sizeof(turbo));
375         if (err) {
376                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
377                         __func__, xsdfec->fec_id);
378                 return -EFAULT;
379         }
380
381         /* Check to see what device tree says about the FEC codes */
382         if (xsdfec->code == XSDFEC_LDPC_CODE) {
383                 dev_err(xsdfec->dev,
384                         "%s: Unable to write Turbo to SDFEC%d check DT",
385                                 __func__, xsdfec->fec_id);
386                 return -EIO;
387         } else if (xsdfec->code == XSDFEC_CODE_INVALID) {
388                 xsdfec->code = XSDFEC_TURBO_CODE;
389         }
390
391         if (xsdfec->wr_protect)
392                 xsdfec_wr_protect(xsdfec, false);
393
394         xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, (xsdfec->code - 1));
395         turbo_write = ((turbo.scale & XSDFEC_TURBO_SCALE_MASK) <<
396                         XSDFEC_TURBO_SCALE_BIT_POS) | turbo.alg;
397         xsdfec_regwrite(xsdfec, XSDFEC_TURBO_ADDR, turbo_write);
398         return err;
399 }
400
401 #define XSDFEC_LDPC_REG_JUMP    (0x10)
402 #define XSDFEC_REG0_N_MASK      (0x0000FFFF)
403 #define XSDFEC_REG0_N_LSB       (0)
404 #define XSDFEC_REG0_K_MASK      (0x7fff0000)
405 #define XSDFEC_REG0_K_LSB       (16)
406 static int
407 xsdfec_reg0_write(struct xsdfec_dev *xsdfec,
408                   u32 n, u32 k, u32 offset)
409 {
410         u32 wdata;
411
412         /* Use only lower 16 bits */
413         if (n & ~XSDFEC_REG0_N_MASK)
414                 dev_err(xsdfec->dev, "N value is beyond 16 bits");
415         n &= XSDFEC_REG0_N_MASK;
416         n <<= XSDFEC_REG0_N_LSB;
417
418         if (k & XSDFEC_REG0_K_MASK)
419                 dev_err(xsdfec->dev, "K value is beyond 16 bits");
420
421         k = ((k << XSDFEC_REG0_K_LSB) & XSDFEC_REG0_K_MASK);
422         wdata = k | n;
423
424         if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
425                                 > XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
426                 dev_err(xsdfec->dev,
427                         "Writing outside of LDPC reg0 space 0x%x",
428                         XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
429                         (offset * XSDFEC_LDPC_REG_JUMP));
430                 return -EINVAL;
431         }
432         xsdfec_regwrite(xsdfec,
433                         XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
434                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
435         return 0;
436 }
437
438 #define XSDFEC_REG1_PSIZE_MASK          (0x000001ff)
439 #define XSDFEC_REG1_NO_PACKING_MASK     (0x00000400)
440 #define XSDFEC_REG1_NO_PACKING_LSB      (10)
441 #define XSDFEC_REG1_NM_MASK             (0x000ff800)
442 #define XSDFEC_REG1_NM_LSB              (11)
443 #define XSDFEC_REG1_BYPASS_MASK (0x00100000)
444 static int
445 xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,
446                   u32 no_packing, u32 nm, u32 offset)
447 {
448         u32 wdata;
449
450         if (psize & ~XSDFEC_REG1_PSIZE_MASK)
451                 dev_err(xsdfec->dev, "Psize is beyond 10 bits");
452         psize &= XSDFEC_REG1_PSIZE_MASK;
453
454         if (no_packing != 0 && no_packing != 1)
455                 dev_err(xsdfec->dev, "No-packing bit register invalid");
456         no_packing = ((no_packing << XSDFEC_REG1_NO_PACKING_LSB) &
457                                         XSDFEC_REG1_NO_PACKING_MASK);
458
459         if (nm & ~(XSDFEC_REG1_NM_MASK >> XSDFEC_REG1_NM_LSB))
460                 dev_err(xsdfec->dev, "NM is beyond 10 bits");
461         nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
462
463         wdata = nm | no_packing | psize;
464         if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
465                 > XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
466                 dev_err(xsdfec->dev,
467                         "Writing outside of LDPC reg1 space 0x%x",
468                         XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
469                         (offset * XSDFEC_LDPC_REG_JUMP));
470                 return -EINVAL;
471         }
472         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
473                 (offset * XSDFEC_LDPC_REG_JUMP), wdata);
474         return 0;
475 }
476
477 #define XSDFEC_REG2_NLAYERS_MASK                (0x000001FF)
478 #define XSDFEC_REG2_NLAYERS_LSB                 (0)
479 #define XSDFEC_REG2_NNMQC_MASK                  (0x000FFE00)
480 #define XSDFEC_REG2_NMQC_LSB                    (9)
481 #define XSDFEC_REG2_NORM_TYPE_MASK              (0x00100000)
482 #define XSDFEC_REG2_NORM_TYPE_LSB               (20)
483 #define XSDFEC_REG2_SPECIAL_QC_MASK             (0x00200000)
484 #define XSDFEC_REG2_SPEICAL_QC_LSB              (21)
485 #define XSDFEC_REG2_NO_FINAL_PARITY_MASK        (0x00400000)
486 #define XSDFEC_REG2_NO_FINAL_PARITY_LSB         (22)
487 #define XSDFEC_REG2_MAX_SCHEDULE_MASK           (0x01800000)
488 #define XSDFEC_REG2_MAX_SCHEDULE_LSB            (23)
489 #define XSDFEC_REG2_LAT_CTRL_MASK               (0xFE000000)
490 #define XSDFEC_REG2_LAT_CTRL_LSB                (25)
491
492 static int
493 xsdfec_reg2_write(struct xsdfec_dev *xsdfec, u32 nlayers, u32 nmqc,
494                   u32 norm_type, u32 special_qc, u32 no_final_parity,
495                   u32 max_schedule, u32 lat_ctrl, u32 offset)
496 {
497         u32 wdata;
498
499         if (nlayers & ~(XSDFEC_REG2_NLAYERS_MASK >>
500                                 XSDFEC_REG2_NLAYERS_LSB))
501                 dev_err(xsdfec->dev, "Nlayers exceeds 9 bits");
502         nlayers &= XSDFEC_REG2_NLAYERS_MASK;
503
504         if (nmqc & ~(XSDFEC_REG2_NNMQC_MASK >> XSDFEC_REG2_NMQC_LSB))
505                 dev_err(xsdfec->dev, "NMQC exceeds 11 bits");
506         nmqc = (nmqc << XSDFEC_REG2_NMQC_LSB) & XSDFEC_REG2_NNMQC_MASK;
507
508         if (norm_type > 1)
509                 dev_err(xsdfec->dev, "Norm type is invalid");
510         norm_type = ((norm_type << XSDFEC_REG2_NORM_TYPE_LSB) &
511                                         XSDFEC_REG2_NORM_TYPE_MASK);
512         if (special_qc > 1)
513                 dev_err(xsdfec->dev, "Special QC in invalid");
514         special_qc = ((special_qc << XSDFEC_REG2_SPEICAL_QC_LSB) &
515                         XSDFEC_REG2_SPECIAL_QC_MASK);
516
517         if (no_final_parity > 1)
518                 dev_err(xsdfec->dev, "No final parity check invalid");
519         no_final_parity =
520                 ((no_final_parity << XSDFEC_REG2_NO_FINAL_PARITY_LSB) &
521                                         XSDFEC_REG2_NO_FINAL_PARITY_MASK);
522         if (max_schedule & ~(XSDFEC_REG2_MAX_SCHEDULE_MASK >>
523                                         XSDFEC_REG2_MAX_SCHEDULE_LSB))
524                 dev_err(xsdfec->dev, "Max Schdule exceeds 2 bits");
525         max_schedule = ((max_schedule << XSDFEC_REG2_MAX_SCHEDULE_LSB) &
526                                 XSDFEC_REG2_MAX_SCHEDULE_MASK);
527         if (lat_ctrl &
528                 ~(XSDFEC_REG2_LAT_CTRL_MASK >> XSDFEC_REG2_LAT_CTRL_LSB))
529                 dev_err(xsdfec->dev, "Lat_Ctrl exceeds 8 bits");
530         lat_ctrl = ((lat_ctrl << XSDFEC_REG2_LAT_CTRL_LSB) &
531                                         XSDFEC_REG2_LAT_CTRL_MASK);
532         wdata = (lat_ctrl | max_schedule | no_final_parity | special_qc |
533                         norm_type | nmqc | nlayers);
534         if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
535                 > XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
536                 dev_err(xsdfec->dev,
537                         "Writing outside of LDPC reg2 space 0x%x",
538                         XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
539                         (offset * XSDFEC_LDPC_REG_JUMP));
540                 return -EINVAL;
541         }
542         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
543                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
544         return 0;
545 }
546
547 #define XSDFEC_REG3_LA_OFF_LSB          (8)
548 #define XSDFEC_REG3_QC_OFF_LSB          (16)
549 static int
550 xsdfec_reg3_write(struct xsdfec_dev *xsdfec, u8 sc_off,
551                   u8 la_off, u16 qc_off, u32 offset)
552 {
553         u32 wdata;
554
555         wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |
556                 (la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);
557         if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
558                 (offset *  XSDFEC_LDPC_REG_JUMP) >
559                         XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
560                 dev_err(xsdfec->dev,
561                         "Writing outside of LDPC reg3 space 0x%x",
562                         XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
563                         (offset * XSDFEC_LDPC_REG_JUMP));
564                 return -EINVAL;
565         }
566         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
567                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
568         return 0;
569 }
570
571 #define XSDFEC_SC_TABLE_DEPTH           (0x3fc)
572 #define XSDFEC_REG_WIDTH_JUMP           (4)
573 static int
574 xsdfec_sc_table_write(struct xsdfec_dev *xsdfec, u32 offset,
575                       u32 *sc_ptr, u32 len)
576 {
577         int reg;
578
579         /*
580          * Writes that go beyond the length of
581          * Shared Scale(SC) table should fail
582          */
583         if ((XSDFEC_REG_WIDTH_JUMP * (offset + len)) > XSDFEC_SC_TABLE_DEPTH) {
584                 dev_err(xsdfec->dev, "Write exceeds SC table length");
585                 return -EINVAL;
586         }
587
588         /*
589          * sc_off tracks the points to the last written location
590          * in the Shared Scale(SC) table. Those shared codes might
591          * be in use. Updating them without quiescing the device
592          * can put the SDFEC device in an indeterminate state
593          */
594         if ((XSDFEC_REG_WIDTH_JUMP * offset) < xsdfec->sc_off) {
595                 dev_err(xsdfec->dev, "Might write to in use shared SC code");
596                 return -EINVAL;
597         }
598
599         for (reg = 0; reg < len; reg++) {
600                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_SC_TABLE_ADDR_BASE +
601                 (offset + reg) *  XSDFEC_REG_WIDTH_JUMP, sc_ptr[reg]);
602         }
603         xsdfec->sc_off = reg + (XSDFEC_REG_WIDTH_JUMP * offset);
604         return reg;
605 }
606
607 #define XSDFEC_LA_TABLE_DEPTH           (0xFFC)
608 static int
609 xsdfec_la_table_write(struct xsdfec_dev *xsdfec, u32 offset,
610                       u32 *la_ptr, u32 len)
611 {
612         int reg;
613
614         if (XSDFEC_REG_WIDTH_JUMP * (offset + len) > XSDFEC_LA_TABLE_DEPTH) {
615                 dev_err(xsdfec->dev, "Write exceeds LA table length");
616                 return -EINVAL;
617         }
618
619         if  (XSDFEC_REG_WIDTH_JUMP * offset < xsdfec->la_off) {
620                 dev_err(xsdfec->dev, "Might write to in use shared LA code");
621                 return -EINVAL;
622         }
623
624         for (reg = 0; reg < len; reg++) {
625                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_LA_TABLE_ADDR_BASE +
626                                 (offset + reg) * XSDFEC_REG_WIDTH_JUMP,
627                                 la_ptr[reg]);
628         }
629         xsdfec->la_off = reg + (offset * XSDFEC_REG_WIDTH_JUMP);
630         return reg;
631 }
632
633 #define XSDFEC_QC_TABLE_DEPTH           (0x7FFC)
634 static int
635 xsdfec_qc_table_write(struct xsdfec_dev *xsdfec,
636                       u32 offset, u32 *qc_ptr, u32 len)
637 {
638         int reg;
639
640         if (XSDFEC_REG_WIDTH_JUMP * (offset + len) > XSDFEC_QC_TABLE_DEPTH) {
641                 dev_err(xsdfec->dev, "Write exceeds QC table length");
642                 return -EINVAL;
643         }
644
645         if (XSDFEC_REG_WIDTH_JUMP * offset < xsdfec->qc_off) {
646                 dev_err(xsdfec->dev, "Might write to in use shared LA code");
647                 return -EINVAL;
648         }
649
650         for (reg = 0; reg < len; reg++) {
651                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_QC_TABLE_ADDR_BASE +
652                  (offset + reg) * XSDFEC_REG_WIDTH_JUMP, qc_ptr[reg]);
653         }
654
655         xsdfec->qc_off = reg + (offset * XSDFEC_REG_WIDTH_JUMP);
656         return reg;
657 }
658
659 static int
660 xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
661 {
662         struct xsdfec_ldpc *ldpc;
663         int err;
664
665         ldpc = kzalloc(sizeof(*ldpc), GFP_KERNEL);
666         if (!ldpc)
667                 return -ENOMEM;
668
669         err = copy_from_user(ldpc, arg, sizeof(*ldpc));
670         if (err) {
671                 dev_err(xsdfec->dev,
672                         "%s failed to copy from user for SDFEC%d",
673                         __func__, xsdfec->fec_id);
674                 return -EFAULT;
675         }
676         if (xsdfec->code == XSDFEC_TURBO_CODE) {
677                 dev_err(xsdfec->dev,
678                         "%s: Unable to write LDPC to SDFEC%d check DT",
679                         __func__, xsdfec->fec_id);
680                 return -EIO;
681         }
682         xsdfec->code = XSDFEC_LDPC_CODE;
683         /* Disable Write Protection before proceeding */
684         if (xsdfec->wr_protect)
685                 xsdfec_wr_protect(xsdfec, false);
686
687         /* Write LDPC to CODE Register */
688         xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, (xsdfec->code - 1));
689         /* Write Reg 0 */
690         err = xsdfec_reg0_write(xsdfec, ldpc->n, ldpc->k, ldpc->code_id);
691         if (err)
692                 goto err_out;
693
694         /* Write Reg 1 */
695         err = xsdfec_reg1_write(xsdfec, ldpc->psize, ldpc->no_packing,
696                                 ldpc->nm, ldpc->code_id);
697         if (err)
698                 goto err_out;
699
700         /* Write Reg 2 */
701         err = xsdfec_reg2_write(xsdfec, ldpc->nlayers, ldpc->nmqc,
702                                 ldpc->norm_type, ldpc->special_qc,
703                                 ldpc->no_final_parity, ldpc->max_schedule,
704                                 ldpc->lat_ctrl, ldpc->code_id);
705         if (err)
706                 goto err_out;
707
708         /* Write Reg 3 */
709         err = xsdfec_reg3_write(xsdfec, ldpc->sc_off,
710                                 ldpc->la_off, ldpc->qc_off, ldpc->code_id);
711         if (err)
712                 goto err_out;
713
714         /* Write Shared Codes */
715         err = xsdfec_sc_table_write(xsdfec, ldpc->sc_off,
716                                     ldpc->sc_table, ldpc->nlayers);
717         if (err < 0)
718                 goto err_out;
719
720         err = xsdfec_la_table_write(xsdfec, 4 * ldpc->la_off,
721                                     ldpc->la_table, ldpc->nlayers);
722         if (err < 0)
723                 goto err_out;
724
725         err = xsdfec_qc_table_write(xsdfec, 4 * ldpc->qc_off,
726                                     ldpc->qc_table, ldpc->nqc);
727         if (err < 0)
728                 goto err_out;
729
730         kfree(ldpc);
731         return 0;
732         /* Error Path */
733 err_out:
734         kfree(ldpc);
735         return err;
736 }
737
738 static int xsdfec_start(struct xsdfec_dev *xsdfec)
739 {
740         u32 regread;
741
742         /* Verify Code is loaded */
743         if (xsdfec->code == XSDFEC_CODE_INVALID) {
744                 dev_err(xsdfec->dev,
745                         "%s : set code before start for SDFEC%d",
746                         __func__, xsdfec->fec_id);
747                 return -EINVAL;
748         }
749         regread = xsdfec_regread(xsdfec, XSDFEC_FEC_CODE_ADDR);
750         regread &= 0x1;
751         if (regread + 1 != xsdfec->code) {
752                 dev_err(xsdfec->dev,
753                         "%s SDFEC HW code does not match driver code",
754                         __func__);
755                 return -EINVAL;
756         }
757         /* Set Order to maintain order */
758         xsdfec->order = XSDFEC_MAINTAIN_ORDER;
759         xsdfec_regwrite(xsdfec, XSDFEC_ORDER_ADDR, (xsdfec->order - 1));
760         /* Set AXIS width */
761         xsdfec_regwrite(xsdfec, XSDFEC_AXIS_WIDTH_ADDR, 0);
762         /* Set AXIS enable */
763         xsdfec_regwrite(xsdfec,
764                         XSDFEC_AXIS_ENABLE_ADDR,
765                         XSDFEC_AXIS_ENABLE_MASK);
766         /* Write Protect Code and Registers */
767         xsdfec_wr_protect(xsdfec, true);
768         /* Done */
769         xsdfec->state = XSDFEC_STARTED;
770         return 0;
771 }
772
773 static int
774 xsdfec_stop(struct xsdfec_dev *xsdfec)
775 {
776         u32 regread;
777
778         if (xsdfec->state != XSDFEC_STARTED)
779                 dev_err(xsdfec->dev, "Device not started correctly");
780         /* Disable Write Protect */
781         xsdfec_wr_protect(xsdfec, false);
782         /* Disable AXIS_ENABLE register */
783         regread = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR);
784         regread &= (~XSDFEC_AXIS_ENABLE_MASK);
785         xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, regread);
786         /* Stop */
787         xsdfec->state = XSDFEC_STOPPED;
788         return 0;
789 }
790
791 /*
792  * Reset will happen asynchronously
793  * since there is no in-band reset register
794  * Prepare driver for reset
795  */
796
797 static int
798 xsdfec_reset_req(struct xsdfec_dev *xsdfec)
799 {
800         xsdfec->state = XSDFEC_INIT;
801         xsdfec->order = XSDFEC_INVALID_ORDER;
802         xsdfec->sc_off = 0;
803         xsdfec->la_off = 0;
804         xsdfec->qc_off = 0;
805         xsdfec->wr_protect = false;
806         atomic_set(&xsdfec->isr_err_count, 0);
807         atomic_set(&xsdfec->uecc_count, 0);
808         atomic_set(&xsdfec->cecc_count, 0);
809         atomic_inc(&xsdfec->reset_count);
810         return 0;
811 }
812
813 static long
814 xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
815 {
816         struct xsdfec_dev *xsdfec = fptr->private_data;
817         void __user *arg = (void __user *)data;
818         int rval = -EINVAL;
819
820         if (!xsdfec)
821                 return rval;
822         if (!arg)
823                 return rval;
824
825         /* In failed state allow only reset and get status IOCTLs */
826         if (xsdfec->state == XSDFEC_NEEDS_RESET &&
827             (cmd != XSDFEC_RESET_REQ && cmd != XSDFEC_GET_STATUS)) {
828                 dev_err(xsdfec->dev,
829                         "SDFEC%d in failed state. Reset Required",
830                         xsdfec->fec_id);
831                 return -EPERM;
832         }
833
834         switch (cmd) {
835         case XSDFEC_START_DEV:
836                 rval = xsdfec_start(xsdfec);
837                 break;
838         case XSDFEC_STOP_DEV:
839                 rval = xsdfec_stop(xsdfec);
840                 break;
841         case XSDFEC_RESET_REQ:
842                 rval = xsdfec_reset_req(xsdfec);
843                 break;
844         case XSDFEC_GET_STATUS:
845                 rval = xsdfec_get_status(xsdfec, arg);
846                 break;
847         case XSDFEC_GET_CONFIG:
848                 rval = xsdfec_get_config(xsdfec, arg);
849                 break;
850         case XSDFEC_SET_IRQ:
851                 rval = xsdfec_set_irq(xsdfec, arg);
852                 break;
853         case XSDFEC_SET_TURBO:
854                 rval = xsdfec_set_turbo(xsdfec, arg);
855                 break;
856         case XSDFEC_ADD_LDPC:
857                 rval  = xsdfec_add_ldpc(xsdfec, arg);
858                 break;
859         default:
860                 /* Should not get here */
861                 dev_err(xsdfec->dev, "Undefined SDFEC IOCTL");
862                 break;
863         }
864         return rval;
865 }
866
867 static unsigned int
868 xsdfec_poll(struct file *file, poll_table *wait)
869 {
870         unsigned int mask;
871         struct xsdfec_dev *xsdfec = file->private_data;
872
873         if (!xsdfec)
874                 return POLLNVAL | POLLHUP;
875
876         poll_wait(file, &xsdfec->waitq, wait);
877
878         /* XSDFEC ISR detected an error */
879         if (xsdfec->state == XSDFEC_NEEDS_RESET)
880                 mask = POLLIN | POLLRDNORM;
881         else
882                 mask = POLLPRI | POLLERR;
883
884         return mask;
885 }
886
887 static const struct file_operations xsdfec_fops = {
888         .owner = THIS_MODULE,
889         .open = xsdfec_dev_open,
890         .release = xsdfec_dev_release,
891         .unlocked_ioctl = xsdfec_dev_ioctl,
892         .poll = xsdfec_poll,
893 };
894
895 static int
896 xsdfec_parse_of(struct xsdfec_dev *xsdfec)
897 {
898         struct device *dev = xsdfec->dev;
899         struct device_node *node = dev->of_node;
900         int rval;
901         const char *fec_code;
902         const char *fec_op_mode;
903
904         rval = of_property_read_string(node,
905                                        "xlnx,sdfec-op-mode",
906                                        &fec_op_mode);
907         if (rval < 0) {
908                 dev_err(dev, "xlnx,sdfec-op-mode not in DT");
909                 return rval;
910         }
911
912         if (!strcasecmp(fec_op_mode, "encode")) {
913                 xsdfec->op_mode = XSDFEC_ENCODE;
914         } else if (!strcasecmp(fec_op_mode, "decode")) {
915                 xsdfec->op_mode = XSDFEC_DECODE;
916         } else {
917                 dev_err(dev, "Encode or Decode not specified in DT");
918                 return -EINVAL;
919         }
920
921         rval = of_property_read_string(node, "xlnx,sdfec-code", &fec_code);
922         if (rval < 0) {
923                 dev_err(dev, "xlnx,sdfec-code not in DT");
924                 return rval;
925         }
926
927         if (!strcasecmp(fec_code, "ldpc")) {
928                 xsdfec->code = XSDFEC_LDPC_CODE;
929         } else if (!strcasecmp(fec_code, "turbo")) {
930                 xsdfec->code = XSDFEC_TURBO_CODE;
931         } else {
932                 dev_err(xsdfec->dev, "Invalid Op Mode in DT");
933                 return -EINVAL;
934         }
935
936         return 0;
937 }
938
939 static void
940 xsdfec_log_ecc_errors(struct xsdfec_dev *xsdfec, u32 ecc_err)
941 {
942         u32 cecc, uecc;
943         int uecc_cnt;
944
945         cecc = ecc_err & XSDFEC_ECC_ISR_SBE;
946         uecc = ecc_err & XSDFEC_ECC_ISR_MBE;
947
948         uecc_cnt = atomic_add_return(hweight32(uecc), &xsdfec->uecc_count);
949         atomic_add(hweight32(cecc), &xsdfec->cecc_count);
950
951         if (uecc_cnt > 0 && uecc_cnt < XSDFEC_ERROR_MAX_THRESHOLD) {
952                 dev_err(xsdfec->dev,
953                         "Multi-bit error on xsdfec%d. Needs reset",
954                         xsdfec->fec_id);
955         }
956
957         /* Clear ECC errors */
958         xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, 0);
959 }
960
961 static void
962 xsdfec_log_isr_errors(struct xsdfec_dev *xsdfec, u32 isr_err)
963 {
964         int isr_err_cnt;
965
966         /* Update ISR error counts */
967         isr_err_cnt = atomic_add_return(hweight32(isr_err),
968                                         &xsdfec->isr_err_count);
969         if (isr_err_cnt > 0 && isr_err_cnt < XSDFEC_ERROR_MAX_THRESHOLD) {
970                 dev_err(xsdfec->dev,
971                         "Tlast,or DIN_WORDS or DOUT_WORDS not correct");
972         }
973
974         /* Clear ISR error status */
975         xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, 0);
976 }
977
978 static void
979 xsdfec_reset_required(struct xsdfec_dev *xsdfec)
980 {
981         xsdfec->state = XSDFEC_NEEDS_RESET;
982 }
983
984 static irqreturn_t
985 xsdfec_irq_thread(int irq, void *dev_id)
986 {
987         struct xsdfec_dev *xsdfec = dev_id;
988         irqreturn_t ret = IRQ_HANDLED;
989         u32 ecc_err;
990         u32 isr_err;
991         bool fatal_err = false;
992
993         WARN_ON(xsdfec->irq != irq);
994
995         /* Mask Interrupts */
996         xsdfec_isr_enable(xsdfec, false);
997         xsdfec_ecc_isr_enable(xsdfec, false);
998
999         /* Read Interrupt Status Registers */
1000         ecc_err = xsdfec_regread(xsdfec, XSDFEC_ECC_ISR_ADDR);
1001         isr_err = xsdfec_regread(xsdfec, XSDFEC_ISR_ADDR);
1002
1003         if (ecc_err & XSDFEC_ECC_ISR_MBE) {
1004                 /* Multi-Bit Errors need Reset */
1005                 xsdfec_log_ecc_errors(xsdfec, ecc_err);
1006                 xsdfec_reset_required(xsdfec);
1007                 fatal_err = true;
1008         } else if (isr_err & XSDFEC_ISR_MASK) {
1009                 /*
1010                  * Tlast, DIN_WORDS and DOUT_WORDS related
1011                  * errors need Reset
1012                  */
1013                 xsdfec_log_isr_errors(xsdfec, isr_err);
1014                 xsdfec_reset_required(xsdfec);
1015                 fatal_err = true;
1016         } else if (ecc_err & XSDFEC_ECC_ISR_SBE) {
1017                 /* Correctable ECC Errors */
1018                 xsdfec_log_ecc_errors(xsdfec, ecc_err);
1019         } else {
1020                 ret = IRQ_NONE;
1021         }
1022
1023         if (fatal_err)
1024                 wake_up_interruptible(&xsdfec->waitq);
1025
1026         /* Unmaks Interrupts */
1027         xsdfec_isr_enable(xsdfec, true);
1028         xsdfec_ecc_isr_enable(xsdfec, true);
1029
1030         return ret;
1031 }
1032
1033 static int
1034 xsdfec_probe(struct platform_device *pdev)
1035 {
1036         struct xsdfec_dev *xsdfec;
1037         struct device *dev;
1038         struct device *dev_create;
1039         struct resource *res;
1040         int err;
1041         bool irq_enabled = true;
1042
1043         xsdfec = devm_kzalloc(&pdev->dev, sizeof(*xsdfec), GFP_KERNEL);
1044         if (!xsdfec)
1045                 return -ENOMEM;
1046
1047         xsdfec->dev = &pdev->dev;
1048         if (atomic_read(&xsdfec_ndevs) > DRIVER_MAX_DEV) {
1049                 dev_err(&pdev->dev,
1050                         "Cannot instantiate more than %d SDFEC instances",
1051                         DRIVER_MAX_DEV);
1052                 return -EINVAL;
1053         }
1054
1055         xsdfec->fec_id = atomic_read(&xsdfec_ndevs);
1056
1057         dev = xsdfec->dev;
1058         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1059         xsdfec->regs = devm_ioremap_resource(dev, res);
1060         if (IS_ERR(xsdfec->regs)) {
1061                 dev_err(dev, "Unable to map resource");
1062                 err = PTR_ERR(xsdfec->regs);
1063                 goto err_xsdfec_dev;
1064         }
1065
1066         xsdfec->irq = platform_get_irq(pdev, 0);
1067         if (xsdfec->irq < 0) {
1068                 dev_dbg(dev, "platform_get_irq failed");
1069                 irq_enabled = false;
1070         }
1071
1072         err = xsdfec_parse_of(xsdfec);
1073         if (err < 0)
1074                 goto err_xsdfec_dev;
1075
1076         /* Save driver private data */
1077         platform_set_drvdata(pdev, xsdfec);
1078
1079         if (irq_enabled) {
1080                 init_waitqueue_head(&xsdfec->waitq);
1081                 /* Register IRQ thread */
1082                 err = devm_request_threaded_irq(dev, xsdfec->irq, NULL,
1083                                                 xsdfec_irq_thread,
1084                                                 IRQF_ONESHOT,
1085                                                 "xilinx-sdfec16",
1086                                                 xsdfec);
1087                 if (err < 0) {
1088                         dev_err(dev, "unable to request IRQ%d", xsdfec->irq);
1089                         goto err_xsdfec_dev;
1090                 }
1091         }
1092
1093         cdev_init(&xsdfec->xsdfec_cdev, &xsdfec_fops);
1094         xsdfec->xsdfec_cdev.owner = THIS_MODULE;
1095         err = cdev_add(&xsdfec->xsdfec_cdev,
1096                        MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id), 1);
1097         if (err < 0) {
1098                 dev_err(dev, "cdev_add failed");
1099                 err = -EIO;
1100                 goto err_xsdfec_dev;
1101         }
1102
1103         if (!xsdfec_class) {
1104                 err = -EIO;
1105                 dev_err(dev, "xsdfec class not created correctly");
1106                 goto err_xsdfec_cdev;
1107         }
1108
1109         dev_create = device_create(xsdfec_class, dev,
1110                                    MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id),
1111                                    xsdfec, "xsdfec%d", xsdfec->fec_id);
1112         if (IS_ERR(dev_create)) {
1113                 dev_err(dev, "unable to create device");
1114                 err = PTR_ERR(dev_create);
1115                 goto err_xsdfec_cdev;
1116         }
1117
1118         atomic_set(&xsdfec->open_count, 1);
1119         dev_info(dev, "XSDFEC%d Probe Successful", xsdfec->fec_id);
1120         atomic_inc(&xsdfec_ndevs);
1121         return 0;
1122
1123         /* Failure cleanup */
1124 err_xsdfec_cdev:
1125         cdev_del(&xsdfec->xsdfec_cdev);
1126 err_xsdfec_dev:
1127         return err;
1128 }
1129
1130 static int
1131 xsdfec_remove(struct platform_device *pdev)
1132 {
1133         struct xsdfec_dev *xsdfec;
1134         struct device *dev = &pdev->dev;
1135
1136         xsdfec = platform_get_drvdata(pdev);
1137         if (!xsdfec)
1138                 return -ENODEV;
1139         dev = xsdfec->dev;
1140         if (!xsdfec_class) {
1141                 dev_err(dev, "xsdfec_class is NULL");
1142                 return -EIO;
1143         }
1144
1145         device_destroy(xsdfec_class,
1146                        MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id));
1147         cdev_del(&xsdfec->xsdfec_cdev);
1148         atomic_dec(&xsdfec_ndevs);
1149         return 0;
1150 }
1151
1152 static const struct of_device_id xsdfec_of_match[] = {
1153         { .compatible = "xlnx,fec-engine", },
1154         { /* end of table */ }
1155 };
1156 MODULE_DEVICE_TABLE(of, xsdfec_of_match);
1157
1158 static struct platform_driver xsdfec_driver = {
1159         .driver = {
1160                 .name = "xilinx-sdfec",
1161                 .of_match_table = xsdfec_of_match,
1162         },
1163         .probe = xsdfec_probe,
1164         .remove =  xsdfec_remove,
1165 };
1166
1167 static int __init xsdfec_init_mod(void)
1168 {
1169         int err;
1170
1171         xsdfec_class = class_create(THIS_MODULE, DRIVER_NAME);
1172         if (IS_ERR(xsdfec_class)) {
1173                 err = PTR_ERR(xsdfec_class);
1174                 pr_err("%s : Unable to register xsdfec class", __func__);
1175                 return err;
1176         }
1177
1178         err = alloc_chrdev_region(&xsdfec_devt,
1179                                   0, DRIVER_MAX_DEV, DRIVER_NAME);
1180         if (err < 0) {
1181                 pr_err("%s : Unable to get major number", __func__);
1182                 goto err_xsdfec_class;
1183         }
1184
1185         err = platform_driver_register(&xsdfec_driver);
1186         if (err < 0) {
1187                 pr_err("%s Unabled to register %s driver",
1188                        __func__, DRIVER_NAME);
1189                 goto err_xsdfec_drv;
1190         }
1191         return 0;
1192
1193         /* Error Path */
1194 err_xsdfec_drv:
1195         unregister_chrdev_region(xsdfec_devt, DRIVER_MAX_DEV);
1196 err_xsdfec_class:
1197         class_destroy(xsdfec_class);
1198         return err;
1199 }
1200
1201 static void __exit xsdfec_cleanup_mod(void)
1202 {
1203         platform_driver_unregister(&xsdfec_driver);
1204         unregister_chrdev_region(xsdfec_devt, DRIVER_MAX_DEV);
1205         class_destroy(xsdfec_class);
1206         xsdfec_class = NULL;
1207 }
1208
1209 module_init(xsdfec_init_mod);
1210 module_exit(xsdfec_cleanup_mod);
1211
1212 MODULE_AUTHOR("Xilinx, Inc");
1213 MODULE_DESCRIPTION("Xilinx SD-FEC16 Driver");
1214 MODULE_LICENSE("GPL");
1215 MODULE_VERSION(DRIVER_VERSION);