1709Swollman// SPDX-License-Identifier: GPL-2.0
27477Sache/*
3709Swollman * JZ47xx ECC common code
437Srgrimes *
537Srgrimes * Copyright (c) 2015 Imagination Technologies
637Srgrimes * Author: Alex Smith <alex.smith@imgtec.com>
737Srgrimes */
837Srgrimes
937Srgrimes#include <linux/clk.h>
1037Srgrimes#include <linux/init.h>
1137Srgrimes#include <linux/module.h>
1237Srgrimes#include <linux/of.h>
1337Srgrimes#include <linux/of_platform.h>
1437Srgrimes#include <linux/platform_device.h>
1537Srgrimes
1637Srgrimes#include "ingenic_ecc.h"
1737Srgrimes
1837Srgrimes/**
1937Srgrimes * ingenic_ecc_calculate() - calculate ECC for a data buffer
2037Srgrimes * @ecc: ECC device.
213843Sdg * @params: ECC parameters.
223843Sdg * @buf: input buffer with raw data.
232164Sdg * @ecc_code: output buffer with ECC.
2437Srgrimes *
2537Srgrimes * Return: 0 on success, -ETIMEDOUT if timed out while waiting for ECC
2637Srgrimes * controller.
2737Srgrimes */
2837Srgrimesint ingenic_ecc_calculate(struct ingenic_ecc *ecc,
2937Srgrimes			  struct ingenic_ecc_params *params,
3037Srgrimes			  const u8 *buf, u8 *ecc_code)
3137Srgrimes{
3237Srgrimes	return ecc->ops->calculate(ecc, params, buf, ecc_code);
3337Srgrimes}
3437Srgrimes
3537Srgrimes/**
3637Srgrimes * ingenic_ecc_correct() - detect and correct bit errors
3737Srgrimes * @ecc: ECC device.
3837Srgrimes * @params: ECC parameters.
3937Srgrimes * @buf: raw data read from the chip.
4037Srgrimes * @ecc_code: ECC read from the chip.
4137Srgrimes *
4237Srgrimes * Given the raw data and the ECC read from the NAND device, detects and
4337Srgrimes * corrects errors in the data.
4437Srgrimes *
4537Srgrimes * Return: the number of bit errors corrected, -EBADMSG if there are too many
4637Srgrimes * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
4737Srgrimes */
4837Srgrimesint ingenic_ecc_correct(struct ingenic_ecc *ecc,
4937Srgrimes			struct ingenic_ecc_params *params,
5037Srgrimes			u8 *buf, u8 *ecc_code)
5137Srgrimes{
5237Srgrimes	return ecc->ops->correct(ecc, params, buf, ecc_code);
5337Srgrimes}
5437Srgrimes
552164Sdg/**
562164Sdg * ingenic_ecc_get() - get the ECC controller device
5737Srgrimes * @np: ECC device tree node.
5837Srgrimes *
5937Srgrimes * Gets the ECC controller device from the specified device tree node. The
6037Srgrimes * device must be released with ingenic_ecc_release() when it is no longer being
613036Sdg * used.
623036Sdg *
633036Sdg * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
641692Sphk * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
6537Srgrimes */
6637Srgrimesstatic struct ingenic_ecc *ingenic_ecc_get(struct device_node *np)
6737Srgrimes{
68872Sache	struct platform_device *pdev;
69872Sache	struct ingenic_ecc *ecc;
70872Sache
71872Sache	pdev = of_find_device_by_node(np);
724091Sache	if (!pdev)
73872Sache		return ERR_PTR(-EPROBE_DEFER);
747219Sjkh
757219Sjkh	if (!platform_get_drvdata(pdev)) {
767219Sjkh		put_device(&pdev->dev);
777219Sjkh		return ERR_PTR(-EPROBE_DEFER);
787219Sjkh	}
791675Sache
807219Sjkh	ecc = platform_get_drvdata(pdev);
817293Sjkh	clk_prepare_enable(ecc->clk);
821675Sache
831675Sache	return ecc;
847259Sjkh}
857259Sjkh
867293Sjkh/**
8737Srgrimes * of_ingenic_ecc_get() - get the ECC controller from a DT node
8837Srgrimes * @of_node: the node that contains an ecc-engine property.
897460Sjkh *
907460Sjkh * Get the ecc-engine property from the given device tree
917460Sjkh * node and pass it to ingenic_ecc_get to do the work.
927460Sjkh *
937460Sjkh * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
947259Sjkh * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
957259Sjkh */
9637Srgrimesstruct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node)
971001Sguido{
987259Sjkh	struct ingenic_ecc *ecc = NULL;
997259Sjkh	struct device_node *np;
100857Sdg
1017259Sjkh	np = of_parse_phandle(of_node, "ecc-engine", 0);
10237Srgrimes
10337Srgrimes	/*
104958Sache	 * If the ecc-engine property is not found, check for the deprecated
105958Sache	 * ingenic,bch-controller property
1061186Srgrimes	 */
1071186Srgrimes	if (!np)
1081186Srgrimes		np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
1091186Srgrimes
1101308Srich	if (np) {
1111186Srgrimes		ecc = ingenic_ecc_get(np);
1121186Srgrimes		of_node_put(np);
1131186Srgrimes	}
1141186Srgrimes	return ecc;
1151186Srgrimes}
1161186Srgrimes
1171186Srgrimes/**
1187238Sache * ingenic_ecc_release() - release the ECC controller device
1197219Sjkh * @ecc: ECC device.
1207238Sache */
1217477Sachevoid ingenic_ecc_release(struct ingenic_ecc *ecc)
1227477Sache{
1237238Sache	clk_disable_unprepare(ecc->clk);
1247238Sache	put_device(ecc->dev);
1257238Sache}
1267238Sache
1277238Sacheint ingenic_ecc_probe(struct platform_device *pdev)
1287294Sjkh{
1297238Sache	struct device *dev = &pdev->dev;
1307238Sache	struct ingenic_ecc *ecc;
1317459Sjkh
1327238Sache	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
1337238Sache	if (!ecc)
1347219Sjkh		return -ENOMEM;
1357459Sjkh
1367238Sache	ecc->ops = device_get_match_data(dev);
1377219Sjkh	if (!ecc->ops)
1387219Sjkh		return -EINVAL;
1397238Sache
1407238Sache	ecc->base = devm_platform_ioremap_resource(pdev, 0);
1417459Sjkh	if (IS_ERR(ecc->base))
1427238Sache		return PTR_ERR(ecc->base);
1437238Sache
1447238Sache	ecc->ops->disable(ecc);
1457477Sache
1467477Sache	ecc->clk = devm_clk_get(dev, NULL);
1477477Sache	if (IS_ERR(ecc->clk)) {
1487477Sache		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
1497477Sache		return PTR_ERR(ecc->clk);
1507477Sache	}
1517477Sache
1527477Sache	mutex_init(&ecc->lock);
1537477Sache
1547477Sache	ecc->dev = dev;
1557477Sache	platform_set_drvdata(pdev, ecc);
1567294Sjkh
1577459Sjkh	return 0;
1587238Sache}
1597238SacheEXPORT_SYMBOL(ingenic_ecc_probe);
1607238Sache