Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * JZ47xx ECC common code
0004  *
0005  * Copyright (c) 2015 Imagination Technologies
0006  * Author: Alex Smith <alex.smith@imgtec.com>
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/platform_device.h>
0014 
0015 #include "ingenic_ecc.h"
0016 
0017 /**
0018  * ingenic_ecc_calculate() - calculate ECC for a data buffer
0019  * @ecc: ECC device.
0020  * @params: ECC parameters.
0021  * @buf: input buffer with raw data.
0022  * @ecc_code: output buffer with ECC.
0023  *
0024  * Return: 0 on success, -ETIMEDOUT if timed out while waiting for ECC
0025  * controller.
0026  */
0027 int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
0028               struct ingenic_ecc_params *params,
0029               const u8 *buf, u8 *ecc_code)
0030 {
0031     return ecc->ops->calculate(ecc, params, buf, ecc_code);
0032 }
0033 
0034 /**
0035  * ingenic_ecc_correct() - detect and correct bit errors
0036  * @ecc: ECC device.
0037  * @params: ECC parameters.
0038  * @buf: raw data read from the chip.
0039  * @ecc_code: ECC read from the chip.
0040  *
0041  * Given the raw data and the ECC read from the NAND device, detects and
0042  * corrects errors in the data.
0043  *
0044  * Return: the number of bit errors corrected, -EBADMSG if there are too many
0045  * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
0046  */
0047 int ingenic_ecc_correct(struct ingenic_ecc *ecc,
0048             struct ingenic_ecc_params *params,
0049             u8 *buf, u8 *ecc_code)
0050 {
0051     return ecc->ops->correct(ecc, params, buf, ecc_code);
0052 }
0053 
0054 /**
0055  * ingenic_ecc_get() - get the ECC controller device
0056  * @np: ECC device tree node.
0057  *
0058  * Gets the ECC controller device from the specified device tree node. The
0059  * device must be released with ingenic_ecc_release() when it is no longer being
0060  * used.
0061  *
0062  * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
0063  * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
0064  */
0065 static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np)
0066 {
0067     struct platform_device *pdev;
0068     struct ingenic_ecc *ecc;
0069 
0070     pdev = of_find_device_by_node(np);
0071     if (!pdev)
0072         return ERR_PTR(-EPROBE_DEFER);
0073 
0074     if (!platform_get_drvdata(pdev)) {
0075         put_device(&pdev->dev);
0076         return ERR_PTR(-EPROBE_DEFER);
0077     }
0078 
0079     ecc = platform_get_drvdata(pdev);
0080     clk_prepare_enable(ecc->clk);
0081 
0082     return ecc;
0083 }
0084 
0085 /**
0086  * of_ingenic_ecc_get() - get the ECC controller from a DT node
0087  * @of_node: the node that contains an ecc-engine property.
0088  *
0089  * Get the ecc-engine property from the given device tree
0090  * node and pass it to ingenic_ecc_get to do the work.
0091  *
0092  * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
0093  * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
0094  */
0095 struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node)
0096 {
0097     struct ingenic_ecc *ecc = NULL;
0098     struct device_node *np;
0099 
0100     np = of_parse_phandle(of_node, "ecc-engine", 0);
0101 
0102     /*
0103      * If the ecc-engine property is not found, check for the deprecated
0104      * ingenic,bch-controller property
0105      */
0106     if (!np)
0107         np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
0108 
0109     if (np) {
0110         ecc = ingenic_ecc_get(np);
0111         of_node_put(np);
0112     }
0113     return ecc;
0114 }
0115 
0116 /**
0117  * ingenic_ecc_release() - release the ECC controller device
0118  * @ecc: ECC device.
0119  */
0120 void ingenic_ecc_release(struct ingenic_ecc *ecc)
0121 {
0122     clk_disable_unprepare(ecc->clk);
0123     put_device(ecc->dev);
0124 }
0125 
0126 int ingenic_ecc_probe(struct platform_device *pdev)
0127 {
0128     struct device *dev = &pdev->dev;
0129     struct ingenic_ecc *ecc;
0130 
0131     ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
0132     if (!ecc)
0133         return -ENOMEM;
0134 
0135     ecc->ops = device_get_match_data(dev);
0136     if (!ecc->ops)
0137         return -EINVAL;
0138 
0139     ecc->base = devm_platform_ioremap_resource(pdev, 0);
0140     if (IS_ERR(ecc->base))
0141         return PTR_ERR(ecc->base);
0142 
0143     ecc->ops->disable(ecc);
0144 
0145     ecc->clk = devm_clk_get(dev, NULL);
0146     if (IS_ERR(ecc->clk)) {
0147         dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
0148         return PTR_ERR(ecc->clk);
0149     }
0150 
0151     mutex_init(&ecc->lock);
0152 
0153     ecc->dev = dev;
0154     platform_set_drvdata(pdev, ecc);
0155 
0156     return 0;
0157 }
0158 EXPORT_SYMBOL(ingenic_ecc_probe);