Commit 15de8c6e authored by Paul Cercueil's avatar Paul Cercueil Committed by Miquel Raynal

mtd: rawnand: ingenic: Separate top-level and SoC specific code

The ingenic-nand driver uses an API provided by the jz4780-bch driver.
This makes it difficult to support other SoCs in the jz4780-bch driver.
To work around this, we separate the API functions from the SoC-specific
code, so that these API functions are SoC-agnostic.
Signed-off-by: default avatarPaul Cercueil <paul@crapouillou.net>
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
parent d74fd06f
...@@ -11,3 +11,20 @@ config MTD_NAND_JZ4780 ...@@ -11,3 +11,20 @@ config MTD_NAND_JZ4780
help help
Enables support for NAND Flash connected to the NEMC on JZ4780 SoC Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
based boards, using the BCH controller for hardware error correction. based boards, using the BCH controller for hardware error correction.
if MTD_NAND_JZ4780
config MTD_NAND_INGENIC_ECC
tristate
config MTD_NAND_JZ4780_BCH
tristate "Hardware BCH support for JZ4780 SoC"
select MTD_NAND_INGENIC_ECC
help
Enable this driver to support the BCH error-correction hardware
present on the JZ4780 SoC from Ingenic.
This driver can also be built as a module. If so, the module
will be called jz4780-bch.
endif # MTD_NAND_JZ4780
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o jz4780_bch.o obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o
obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o
obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o
// SPDX-License-Identifier: GPL-2.0
/*
* JZ47xx ECC common code
*
* Copyright (c) 2015 Imagination Technologies
* Author: Alex Smith <alex.smith@imgtec.com>
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "ingenic_ecc.h"
/**
* ingenic_ecc_calculate() - calculate ECC for a data buffer
* @ecc: ECC device.
* @params: ECC parameters.
* @buf: input buffer with raw data.
* @ecc_code: output buffer with ECC.
*
* Return: 0 on success, -ETIMEDOUT if timed out while waiting for ECC
* controller.
*/
int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
const u8 *buf, u8 *ecc_code)
{
return ecc->ops->calculate(ecc, params, buf, ecc_code);
}
EXPORT_SYMBOL(ingenic_ecc_calculate);
/**
* ingenic_ecc_correct() - detect and correct bit errors
* @ecc: ECC device.
* @params: ECC parameters.
* @buf: raw data read from the chip.
* @ecc_code: ECC read from the chip.
*
* Given the raw data and the ECC read from the NAND device, detects and
* corrects errors in the data.
*
* Return: the number of bit errors corrected, -EBADMSG if there are too many
* errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
*/
int ingenic_ecc_correct(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
u8 *buf, u8 *ecc_code)
{
return ecc->ops->correct(ecc, params, buf, ecc_code);
}
EXPORT_SYMBOL(ingenic_ecc_correct);
/**
* ingenic_ecc_get() - get the ECC controller device
* @np: ECC device tree node.
*
* Gets the ECC controller device from the specified device tree node. The
* device must be released with ingenic_ecc_release() when it is no longer being
* used.
*
* Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
* PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
*/
static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np)
{
struct platform_device *pdev;
struct ingenic_ecc *ecc;
pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev))
return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
ecc = platform_get_drvdata(pdev);
clk_prepare_enable(ecc->clk);
return ecc;
}
/**
* of_ingenic_ecc_get() - get the ECC controller from a DT node
* @of_node: the node that contains a bch-controller property.
*
* Get the bch-controller property from the given device tree
* node and pass it to ingenic_ecc_get to do the work.
*
* Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
* PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
*/
struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node)
{
struct ingenic_ecc *ecc = NULL;
struct device_node *np;
np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
if (np) {
ecc = ingenic_ecc_get(np);
of_node_put(np);
}
return ecc;
}
EXPORT_SYMBOL(of_ingenic_ecc_get);
/**
* ingenic_ecc_release() - release the ECC controller device
* @ecc: ECC device.
*/
void ingenic_ecc_release(struct ingenic_ecc *ecc)
{
clk_disable_unprepare(ecc->clk);
put_device(ecc->dev);
}
EXPORT_SYMBOL(ingenic_ecc_release);
int ingenic_ecc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ingenic_ecc *ecc;
struct resource *res;
ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
if (!ecc)
return -ENOMEM;
ecc->ops = device_get_match_data(dev);
if (!ecc->ops)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ecc->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ecc->base))
return PTR_ERR(ecc->base);
ecc->ops->disable(ecc);
ecc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ecc->clk)) {
dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
return PTR_ERR(ecc->clk);
}
mutex_init(&ecc->lock);
ecc->dev = dev;
platform_set_drvdata(pdev, ecc);
return 0;
}
EXPORT_SYMBOL(ingenic_ecc_probe);
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__
#define __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__
#include <linux/compiler_types.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <uapi/asm-generic/errno-base.h>
struct clk;
struct device;
struct ingenic_ecc;
struct platform_device;
/**
* struct ingenic_ecc_params - ECC parameters
* @size: data bytes per ECC step.
* @bytes: ECC bytes per step.
* @strength: number of correctable bits per ECC step.
*/
struct ingenic_ecc_params {
int size;
int bytes;
int strength;
};
#if IS_ENABLED(CONFIG_MTD_NAND_INGENIC_ECC)
int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
const u8 *buf, u8 *ecc_code);
int ingenic_ecc_correct(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params, u8 *buf,
u8 *ecc_code);
void ingenic_ecc_release(struct ingenic_ecc *ecc);
struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np);
#else /* CONFIG_MTD_NAND_INGENIC_ECC */
int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
const u8 *buf, u8 *ecc_code)
{
return -ENODEV;
}
int ingenic_ecc_correct(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params, u8 *buf,
u8 *ecc_code)
{
return -ENODEV;
}
void ingenic_ecc_release(struct ingenic_ecc *ecc)
{
}
struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
{
return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_MTD_NAND_INGENIC_ECC */
struct ingenic_ecc_ops {
void (*disable)(struct ingenic_ecc *ecc);
int (*calculate)(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
const u8 *buf, u8 *ecc_code);
int (*correct)(struct ingenic_ecc *ecc,
struct ingenic_ecc_params *params,
u8 *buf, u8 *ecc_code);
};
struct ingenic_ecc {
struct device *dev;
const struct ingenic_ecc_ops *ops;
void __iomem *base;
struct clk *clk;
struct mutex lock;
};
int ingenic_ecc_probe(struct platform_device *pdev);
#endif /* __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__ */
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/jz4780-nemc.h> #include <linux/jz4780-nemc.h>
#include "jz4780_bch.h" #include "ingenic_ecc.h"
#define DRV_NAME "ingenic-nand" #define DRV_NAME "ingenic-nand"
...@@ -40,7 +40,7 @@ struct ingenic_nand_cs { ...@@ -40,7 +40,7 @@ struct ingenic_nand_cs {
struct ingenic_nfc { struct ingenic_nfc {
struct device *dev; struct device *dev;
struct jz4780_bch *bch; struct ingenic_ecc *ecc;
struct nand_controller controller; struct nand_controller controller;
unsigned int num_banks; unsigned int num_banks;
struct list_head chips; struct list_head chips;
...@@ -124,11 +124,11 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, ...@@ -124,11 +124,11 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
{ {
struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
struct jz4780_bch_params params; struct ingenic_ecc_params params;
/* /*
* Don't need to generate the ECC when reading, BCH does it for us as * Don't need to generate the ECC when reading, the ECC engine does it
* part of decoding/correction. * for us as part of decoding/correction.
*/ */
if (nand->reading) if (nand->reading)
return 0; return 0;
...@@ -137,7 +137,7 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, ...@@ -137,7 +137,7 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
params.bytes = nand->chip.ecc.bytes; params.bytes = nand->chip.ecc.bytes;
params.strength = nand->chip.ecc.strength; params.strength = nand->chip.ecc.strength;
return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code); return ingenic_ecc_calculate(nfc->ecc, &params, dat, ecc_code);
} }
static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat, static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
...@@ -145,13 +145,13 @@ static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat, ...@@ -145,13 +145,13 @@ static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
{ {
struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
struct jz4780_bch_params params; struct ingenic_ecc_params params;
params.size = nand->chip.ecc.size; params.size = nand->chip.ecc.size;
params.bytes = nand->chip.ecc.bytes; params.bytes = nand->chip.ecc.bytes;
params.strength = nand->chip.ecc.strength; params.strength = nand->chip.ecc.strength;
return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc); return ingenic_ecc_correct(nfc->ecc, &params, dat, read_ecc);
} }
static int ingenic_nand_attach_chip(struct nand_chip *chip) static int ingenic_nand_attach_chip(struct nand_chip *chip)
...@@ -165,8 +165,8 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) ...@@ -165,8 +165,8 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
switch (chip->ecc.mode) { switch (chip->ecc.mode) {
case NAND_ECC_HW: case NAND_ECC_HW:
if (!nfc->bch) { if (!nfc->ecc) {
dev_err(nfc->dev, "HW BCH selected, but BCH controller not found\n"); dev_err(nfc->dev, "HW ECC selected, but ECC controller not found\n");
return -ENODEV; return -ENODEV;
} }
...@@ -176,7 +176,7 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) ...@@ -176,7 +176,7 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
/* fall through */ /* fall through */
case NAND_ECC_SOFT: case NAND_ECC_SOFT:
dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
(nfc->bch) ? "hardware BCH" : "software ECC", (nfc->ecc) ? "hardware ECC" : "software ECC",
chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
break; break;
case NAND_ECC_NONE: case NAND_ECC_NONE:
...@@ -354,12 +354,12 @@ static int ingenic_nand_probe(struct platform_device *pdev) ...@@ -354,12 +354,12 @@ static int ingenic_nand_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
/* /*
* Check for BCH HW before we call nand_scan_ident, to prevent us from * Check for ECC HW before we call nand_scan_ident, to prevent us from
* having to call it again if the BCH driver returns -EPROBE_DEFER. * having to call it again if the ECC driver returns -EPROBE_DEFER.
*/ */
nfc->bch = of_jz4780_bch_get(dev->of_node); nfc->ecc = of_ingenic_ecc_get(dev->of_node);
if (IS_ERR(nfc->bch)) if (IS_ERR(nfc->ecc))
return PTR_ERR(nfc->bch); return PTR_ERR(nfc->ecc);
nfc->dev = dev; nfc->dev = dev;
nfc->num_banks = num_banks; nfc->num_banks = num_banks;
...@@ -369,8 +369,8 @@ static int ingenic_nand_probe(struct platform_device *pdev) ...@@ -369,8 +369,8 @@ static int ingenic_nand_probe(struct platform_device *pdev)
ret = ingenic_nand_init_chips(nfc, pdev); ret = ingenic_nand_init_chips(nfc, pdev);
if (ret) { if (ret) {
if (nfc->bch) if (nfc->ecc)
jz4780_bch_release(nfc->bch); ingenic_ecc_release(nfc->ecc);
return ret; return ret;
} }
...@@ -382,8 +382,8 @@ static int ingenic_nand_remove(struct platform_device *pdev) ...@@ -382,8 +382,8 @@ static int ingenic_nand_remove(struct platform_device *pdev)
{ {
struct ingenic_nfc *nfc = platform_get_drvdata(pdev); struct ingenic_nfc *nfc = platform_get_drvdata(pdev);
if (nfc->bch) if (nfc->ecc)
jz4780_bch_release(nfc->bch); ingenic_ecc_release(nfc->ecc);
ingenic_nand_cleanup_chips(nfc); ingenic_nand_cleanup_chips(nfc);
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* JZ4780 BCH controller * JZ4780 BCH controller driver
* *
* Copyright (c) 2015 Imagination Technologies * Copyright (c) 2015 Imagination Technologies
* Author: Alex Smith <alex.smith@imgtec.com> * Author: Alex Smith <alex.smith@imgtec.com>
...@@ -8,18 +8,15 @@ ...@@ -8,18 +8,15 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include "jz4780_bch.h" #include "ingenic_ecc.h"
#define BCH_BHCR 0x0 #define BCH_BHCR 0x0
#define BCH_BHCCR 0x8 #define BCH_BHCCR 0x8
...@@ -62,15 +59,8 @@ ...@@ -62,15 +59,8 @@
/* Timeout for BCH calculation/correction. */ /* Timeout for BCH calculation/correction. */
#define BCH_TIMEOUT_US 100000 #define BCH_TIMEOUT_US 100000
struct jz4780_bch { static void jz4780_bch_reset(struct ingenic_ecc *bch,
struct device *dev; struct ingenic_ecc_params *params, bool encode)
void __iomem *base;
struct clk *clk;
struct mutex lock;
};
static void jz4780_bch_reset(struct jz4780_bch *bch,
struct jz4780_bch_params *params, bool encode)
{ {
u32 reg; u32 reg;
...@@ -90,13 +80,13 @@ static void jz4780_bch_reset(struct jz4780_bch *bch, ...@@ -90,13 +80,13 @@ static void jz4780_bch_reset(struct jz4780_bch *bch,
writel(reg, bch->base + BCH_BHCR); writel(reg, bch->base + BCH_BHCR);
} }
static void jz4780_bch_disable(struct jz4780_bch *bch) static void jz4780_bch_disable(struct ingenic_ecc *bch)
{ {
writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR); writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
} }
static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, static void jz4780_bch_write_data(struct ingenic_ecc *bch, const void *buf,
size_t size) size_t size)
{ {
size_t size32 = size / sizeof(u32); size_t size32 = size / sizeof(u32);
...@@ -113,7 +103,7 @@ static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, ...@@ -113,7 +103,7 @@ static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
writeb(*src8++, bch->base + BCH_BHDR); writeb(*src8++, bch->base + BCH_BHDR);
} }
static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, static void jz4780_bch_read_parity(struct ingenic_ecc *bch, void *buf,
size_t size) size_t size)
{ {
size_t size32 = size / sizeof(u32); size_t size32 = size / sizeof(u32);
...@@ -143,7 +133,7 @@ static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, ...@@ -143,7 +133,7 @@ static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
} }
} }
static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, static bool jz4780_bch_wait_complete(struct ingenic_ecc *bch, unsigned int irq,
u32 *status) u32 *status)
{ {
u32 reg; u32 reg;
...@@ -167,17 +157,8 @@ static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, ...@@ -167,17 +157,8 @@ static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
return true; return true;
} }
/** static int jz4780_calculate(struct ingenic_ecc *bch,
* jz4780_bch_calculate() - calculate ECC for a data buffer struct ingenic_ecc_params *params,
* @bch: BCH device.
* @params: BCH parameters.
* @buf: input buffer with raw data.
* @ecc_code: output buffer with ECC.
*
* Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
* controller.
*/
int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
const u8 *buf, u8 *ecc_code) const u8 *buf, u8 *ecc_code)
{ {
int ret = 0; int ret = 0;
...@@ -198,22 +179,9 @@ int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *param ...@@ -198,22 +179,9 @@ int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *param
mutex_unlock(&bch->lock); mutex_unlock(&bch->lock);
return ret; return ret;
} }
EXPORT_SYMBOL(jz4780_bch_calculate);
static int jz4780_correct(struct ingenic_ecc *bch,
/** struct ingenic_ecc_params *params,
* jz4780_bch_correct() - detect and correct bit errors
* @bch: BCH device.
* @params: BCH parameters.
* @buf: raw data read from the chip.
* @ecc_code: ECC read from the chip.
*
* Given the raw data and the ECC read from the NAND device, detects and
* corrects errors in the data.
*
* Return: the number of bit errors corrected, -EBADMSG if there are too many
* errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
*/
int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
u8 *buf, u8 *ecc_code) u8 *buf, u8 *ecc_code)
{ {
u32 reg, mask, index; u32 reg, mask, index;
...@@ -260,110 +228,30 @@ int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params, ...@@ -260,110 +228,30 @@ int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
mutex_unlock(&bch->lock); mutex_unlock(&bch->lock);
return ret; return ret;
} }
EXPORT_SYMBOL(jz4780_bch_correct);
/**
* jz4780_bch_get() - get the BCH controller device
* @np: BCH device tree node.
*
* Gets the BCH controller device from the specified device tree node. The
* device must be released with jz4780_bch_release() when it is no longer being
* used.
*
* Return: a pointer to jz4780_bch, errors are encoded into the pointer.
* PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
*/
static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
{
struct platform_device *pdev;
struct jz4780_bch *bch;
pdev = of_find_device_by_node(np);
if (!pdev)
return ERR_PTR(-EPROBE_DEFER);
bch = platform_get_drvdata(pdev);
if (!bch) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(bch->clk);
return bch;
}
/**
* of_jz4780_bch_get() - get the BCH controller from a DT node
* @of_node: the node that contains a bch-controller property.
*
* Get the bch-controller property from the given device tree
* node and pass it to jz4780_bch_get to do the work.
*
* Return: a pointer to jz4780_bch, errors are encoded into the pointer.
* PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
*/
struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
{
struct jz4780_bch *bch = NULL;
struct device_node *np;
np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
if (np) {
bch = jz4780_bch_get(np);
of_node_put(np);
}
return bch;
}
EXPORT_SYMBOL(of_jz4780_bch_get);
/**
* jz4780_bch_release() - release the BCH controller device
* @bch: BCH device.
*/
void jz4780_bch_release(struct jz4780_bch *bch)
{
clk_disable_unprepare(bch->clk);
put_device(bch->dev);
}
EXPORT_SYMBOL(jz4780_bch_release);
static int jz4780_bch_probe(struct platform_device *pdev) static int jz4780_bch_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct ingenic_ecc *bch;
struct jz4780_bch *bch; int ret;
struct resource *res;
bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
if (!bch)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bch->base = devm_ioremap_resource(dev, res);
if (IS_ERR(bch->base))
return PTR_ERR(bch->base);
jz4780_bch_disable(bch);
bch->clk = devm_clk_get(dev, NULL); ret = ingenic_ecc_probe(pdev);
if (IS_ERR(bch->clk)) { if (ret)
dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk)); return ret;
return PTR_ERR(bch->clk);
}
bch = platform_get_drvdata(pdev);
clk_set_rate(bch->clk, BCH_CLK_RATE); clk_set_rate(bch->clk, BCH_CLK_RATE);
mutex_init(&bch->lock);
bch->dev = dev;
platform_set_drvdata(pdev, bch);
return 0; return 0;
} }
static const struct ingenic_ecc_ops jz4780_bch_ops = {
.disable = jz4780_bch_disable,
.calculate = jz4780_calculate,
.correct = jz4780_correct,
};
static const struct of_device_id jz4780_bch_dt_match[] = { static const struct of_device_id jz4780_bch_dt_match[] = {
{ .compatible = "ingenic,jz4780-bch" }, { .compatible = "ingenic,jz4780-bch", .data = &jz4780_bch_ops },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match); MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* JZ4780 BCH controller
*
* Copyright (c) 2015 Imagination Technologies
* Author: Alex Smith <alex.smith@imgtec.com>
*/
#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__
#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
#include <linux/types.h>
struct device;
struct device_node;
struct jz4780_bch;
/**
* struct jz4780_bch_params - BCH parameters
* @size: data bytes per ECC step.
* @bytes: ECC bytes per step.
* @strength: number of correctable bits per ECC step.
*/
struct jz4780_bch_params {
int size;
int bytes;
int strength;
};
int jz4780_bch_calculate(struct jz4780_bch *bch,
struct jz4780_bch_params *params,
const u8 *buf, u8 *ecc_code);
int jz4780_bch_correct(struct jz4780_bch *bch,
struct jz4780_bch_params *params, u8 *buf,
u8 *ecc_code);
void jz4780_bch_release(struct jz4780_bch *bch);
struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment